钓鱼 | 蓝队—反钓鱼的策略提供

admin 2025年1月5日22:43:55评论7 views字数 29811阅读99分22秒阅读模式

原文链接:https://xz.aliyun.com/t/16858

作者:Bat-Hibara

0x1 前言

鄙人最近在某某群中寻找到了一个不知道谁的后门,心血来潮写下此文,以此提供一些蓝队简易反钓鱼的策略

ps.(下篇文章就写红队如何高概率钓鱼,期待一下)

本文所用环境:VS2022

0x2 总思路

通过对IP查找,特殊文件名,文件编译器,启动项的检查,选出第一批可疑进程,再对其筛选,最终以弹窗的形式呈现

0x3 流量方面

1.获取所有进程的IP连接:

#include<iostream>#include<fstream>#include<string>#include<vector>#include<winsock2.h>#include<iphlpapi.h>#include<windows.h>#include<tlhelp32.h>#include<psapi.h>#include<ws2tcpip.h>#pragma comment(lib, "iphlpapi.lib")#pragma comment(lib, "ws2_32.lib")#pragma comment(lib, "user32.lib")#pragma comment(lib, "advapi32.lib"// For UAC check and elevation// Function to get the process name given its PIDstd::wstring getProcessName(DWORD pid) {    wchar_t processName[MAX_PATH] = L"<未知>";    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);    if (hProcess != NULL) {        HMODULE hMod;        DWORD cbNeeded;        if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {            GetModuleBaseNameW(hProcess, hMod, processName, sizeof(processName) / sizeof(wchar_t));        }        CloseHandle(hProcess);    }    return std::wstring(processName);}// Function to get the process path given its PIDstd::wstring getProcessPath(DWORD pid) {    wchar_t processPath[MAX_PATH] = L"<未知>";    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);    if (hProcess != NULL) {        GetModuleFileNameExW(hProcess, NULL, processPath, sizeof(processPath) / sizeof(wchar_t));        CloseHandle(hProcess);    }    return std::wstring(processPath);}// Function to enumerate all network connectionsvoid enumerateConnections() {    PMIB_TCPTABLE2 tcpTable;    DWORD dwSize = 0;    DWORD dwRetVal = 0;    tcpTable = (MIB_TCPTABLE2*)malloc(sizeof(MIB_TCPTABLE2));    if (tcpTable == NULL) {        std::cerr << "分配内存时出错" << std::endl;        return;    }    dwSize = sizeof(MIB_TCPTABLE2);    if ((dwRetVal = GetTcpTable2(tcpTable, &dwSize, TRUE)) == ERROR_INSUFFICIENT_BUFFER) {        free(tcpTable);        tcpTable = (MIB_TCPTABLE2*)malloc(dwSize);        if (tcpTable == NULL) {            std::cerr << "分配内存时出错" << std::endl;            return;        }    }    if ((dwRetVal = GetTcpTable2(tcpTable, &dwSize, TRUE)) == NO_ERROR) {        char ipStringBuffer[INET_ADDRSTRLEN];        std::wstring output;        for (int i = 0; i < (int)tcpTable->dwNumEntries; i++) {            inet_ntop(AF_INET, &tcpTable->table[i].dwRemoteAddr, ipStringBuffer, INET_ADDRSTRLEN);            std::string remoteIp(ipStringBuffer);            DWORD pid = tcpTable->table[i].dwOwningPid;            std::wstring processName = getProcessName(pid);            std::wstring processPath = getProcessPath(pid);            output += L"程序名称: " + processName + L"n连接的IP: " + std::wstring(remoteIp.begin(), remoteIp.end()) +                L"n程序路径: " + processPath + L"n---------------------------------n";        }        // Show the output in a message box        if (!output.empty()) {            MessageBoxW(NULL, output.c_str(), L"IP 和进程监控", MB_OK);        }        else {            MessageBoxW(NULL, L"未找到任何连接信息。", L"IP 和进程监控", MB_OK);        }    }    else {        std::cerr << "GetTcpTable2 调用失败,错误代码: " << dwRetVal << std::endl;    }    if (tcpTable != NULL) {        free(tcpTable);        tcpTable = NULL;    }}// Function to check if the program is running as administratorbool isRunningAsAdmin() {    BOOL fIsRunAsAdmin = FALSE;    PSID pAdministratorsGroup = NULL;    SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;    if (AllocateAndInitializeSid(&NtAuthority, 2,        SECURITY_BUILTIN_DOMAIN_RID,        DOMAIN_ALIAS_RID_ADMINS,        0, 0, 0, 0, 0, 0,        &pAdministratorsGroup))    {        if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin)) {            fIsRunAsAdmin = FALSE;        }        FreeSid(pAdministratorsGroup);    }    return fIsRunAsAdmin;}// Function to restart the program with UAC elevationvoid runAsAdmin() {    wchar_t szPath[MAX_PATH];    if (GetModuleFileNameW(NULL, szPath, ARRAYSIZE(szPath))) {        SHELLEXECUTEINFOW sei = { sizeof(sei) };        sei.lpVerb = L"runas";        sei.lpFile = szPath;        sei.hwnd = NULL;        sei.nShow = SW_NORMAL;        if (!ShellExecuteExW(&sei)) {            DWORD dwError = GetLastError();            if (dwError == ERROR_CANCELLED) {                MessageBoxW(NULL, L"用户拒绝了权限提升请求。", L"错误", MB_OK);            }        }        else {            ExitProcess(0); // Terminate the current process since it's being restarted with elevation        }    }}int main() {    // Step 1: Check for administrator privileges    if (!isRunningAsAdmin()) {        MessageBoxW(NULL, L"尝试以管理员权限运行...", L"提示", MB_OK);        runAsAdmin();        return 0;    }    // Step 2: Enumerate all connections    enumerateConnections();    return 0;}

功能解释:

头文件和库的导入部分

#include<iostream>#include<fstream>#include<string>#include<vector>#include<winsock2.h>#include<iphlpapi.h>#include<windows.h>#include<tlhelp32.h>#include<psapi.h>#include<ws2tcpip.h>#pragma comment(lib, "iphlpapi.lib")#pragma comment(lib, "ws2_32.lib")#pragma comment(lib, "user32.lib")#pragma comment(lib, "advapi32.lib"// For UAC check and elevation
功能说明:
  • 头文件:
    • iostream
      ,fstream: 用于输入输出流操作。
    • string
      ,vector: 提供字符串处理和动态数组的支持。
    • winsock2.h
      : 提供 Windows 套接字(网络编程)接口。
    • iphlpapi.h
      : 包含与 IP 地址和网络接口相关的 API。
    • windows.h
      : Windows API 的通用头文件,提供多种核心功能。
    • tlhelp32.h
      : 提供与进程、线程快照相关的 API。
    • psapi.h
      : 用于获取进程相关信息(如模块和内存使用情况)。
    • ws2tcpip.h
      : 提供对 IPv6、地址转换和其他网络功能的支持。
  • 库链接:
    • iphlpapi.lib
      : 提供 IP 助手 API 的支持。
    • ws2_32.lib
      : 提供套接字编程所需的基础支持。
    • user32.lib
      : 提供与 GUI 和用户界面交互相关的 API。
    • advapi32.lib
      : 提供与权限提升(如 UAC 检查)相关的 API。

获取进程名称的函数

std::wstring getProcessName(DWORD pid) {wchar_t processName[MAX_PATH] = L"<未知>";    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);if (hProcess != NULL) {        HMODULE hMod;        DWORD cbNeeded;if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {            GetModuleBaseNameW(hProcess, hMod, processName, sizeof(processName) / sizeof(wchar_t));        }        CloseHandle(hProcess);    }return std::wstring(processName);}
功能说明:
  • 输入:
    • pid
      : 进程的 PID(Process ID)。
  • 输出:
    • 该 PID 对应的进程名称。
  • 详细逻辑:
    • PROCESS_QUERY_INFORMATION
      : 允许查询进程信息。
    • PROCESS_VM_READ
      : 允许读取进程的虚拟内存。
    1. 调用OpenProcess打开目标进程句柄,权限为PROCESS_QUERY_INFORMATION | PROCESS_VM_READ
    2. 使用EnumProcessModules获取进程的第一个模块句柄(通常是主程序)。
    3. 调用GetModuleBaseNameW获取该模块(即程序)的名称。
    4. 若无法获取,返回默认值<未知>
    5. 关闭进程句柄以释放资源。

获取进程路径的函数

std::wstring getProcessPath(DWORD pid) {wchar_t processPath[MAX_PATH] = L"<未知>";    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);if (hProcess != NULL) {        GetModuleFileNameExW(hProcess, NULL, processPath, sizeof(processPath) / sizeof(wchar_t));        CloseHandle(hProcess);    }return std::wstring(processPath);}
功能说明:
  • 输入:
    • pid
      : 进程的 PID(Process ID)。
  • 输出:
    • 该 PID 对应的可执行文件完整路径。
  • 详细逻辑:
    • 与获取进程名称类似,但这里使用GetModuleFileNameExW,返回的是可执行文件的完整路径(包括磁盘路径)。
    • 如果进程无法访问,返回默认值<未知>

枚举所有网络连接的函数

voidenumerateConnections(){    PMIB_TCPTABLE2 tcpTable;    DWORD dwSize = 0;    DWORD dwRetVal = 0;    tcpTable = (MIB_TCPTABLE2*)malloc(sizeof(MIB_TCPTABLE2));if (tcpTable == NULL) {        std::cerr << "分配内存时出错" << std::endl;return;    }
功能说明:
  • 步骤 1:分配空间
    • 调用mallocMIB_TCPTABLE2分配内存,用于存储 TCP 连接表。
cpp复制代码if ((dwRetVal = GetTcpTable2(tcpTable, &dwSize, TRUE)) == ERROR_INSUFFICIENT_BUFFER) {free(tcpTable);        tcpTable = (MIB_TCPTABLE2*)malloc(dwSize);if (tcpTable == NULL) {            std::cerr << "分配内存时出错" << std::endl;return;        }    }
  • 步骤 2:获取 TCP 连接表
    • 使用GetTcpTable2获取当前的 TCP 连接表。
    • 如果内存不足,重新分配足够的空间。
cpp复制代码if ((dwRetVal = GetTcpTable2(tcpTable, &dwSize, TRUE)) == NO_ERROR) {char ipStringBuffer[INET_ADDRSTRLEN];        std::wstring output;for (int i = 0; i < (int)tcpTable->dwNumEntries; i++) {inet_ntop(AF_INET, &tcpTable->table[i].dwRemoteAddr, ipStringBuffer, INET_ADDRSTRLEN);std::string remoteIp(ipStringBuffer);            DWORD pid = tcpTable->table[i].dwOwningPid;            std::wstring processName = getProcessName(pid);            std::wstring processPath = getProcessPath(pid);            output += L"程序名称: " + processName + L"n连接的IP: " + std::wstring(remoteIp.begin(), remoteIp.end()) +L"n程序路径: " + processPath + L"n---------------------------------n";        }
  • 步骤 3:解析每个连接
    1. 遍历tcpTable->table中的每个 TCP 连接项。
    2. 使用inet_ntop将二进制的远程 IP 地址转换为字符串形式。
    3. 调用getProcessNamegetProcessPath获取连接对应进程的名称和路径。
    4. 将结果拼接到output中。
cpp复制代码if(!output.empty()) {MessageBoxW(NULL, output.c_str(), L"IP 和进程监控", MB_OK);        }else {MessageBoxW(NULL, L"未找到任何连接信息。", L"IP 和进程监控", MB_OK);        }    }
  • 步骤 4:输出结果
    • 如果存在连接信息,将结果显示在消息框中。
    • 如果没有任何连接,显示提示信息。
cpp复制代码if (tcpTable != NULL) {free(tcpTable);        tcpTable = NULL;    }
  • 步骤 5:释放资源
    • 释放之前分配的内存,避免内存泄漏。

检查程序是否以管理员权限运行

bool isRunningAsAdmin() {BOOL fIsRunAsAdmin = FALSE;    PSID pAdministratorsGroup = NULL;    SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;if (AllocateAndInitializeSid(&NtAuthority, 2,        SECURITY_BUILTIN_DOMAIN_RID,        DOMAIN_ALIAS_RID_ADMINS,000000,        &pAdministratorsGroup))    {if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin)) {            fIsRunAsAdmin = FALSE;        }        FreeSid(pAdministratorsGroup);    }return fIsRunAsAdmin;}
功能说明:
  • 通过CheckTokenMembership检查当前用户是否属于管理员组。
  • 如果属于管理员组,返回true;否则返回false

请求权限提升

voidrunAsAdmin(){wchar_t szPath[MAX_PATH];if (GetModuleFileNameW(NULL, szPath, ARRAYSIZE(szPath))) {        SHELLEXECUTEINFOW sei = { sizeof(sei) };        sei.lpVerb = L"runas";        sei.lpFile = szPath;        sei.hwnd = NULL;        sei.nShow = SW_NORMAL;if (!ShellExecuteExW(&sei)) {            DWORD dwError = GetLastError();if (dwError == ERROR_CANCELLED) {MessageBoxW(NULLL"用户拒绝了权限提升请求。"L"错误", MB_OK);            }        }else {ExitProcess(0);        }    }}
功能说明:
  • 如果程序未以管理员权限运行,调用ShellExecuteExW重新启动程序,并请求权限提升。

主函数

intmain() {if (!isRunningAsAdmin()) {        MessageBoxW(NULL, L"尝试以管理员权限运行...", L"提示", MB_OK);        runAsAdmin();return0;    }    enumerateConnections();return0;}
功能说明:
  1. 检查程序是否以管理员权限运行。
  2. 如果未以管理员权限运行,尝试权限提升。
  3. 如果权限足够,则调用enumerateConnections列出所有网络连接。

2.过筛-192,127,0等

code:

#include<iostream>#include<fstream>#include<string>#include<vector>#include<winsock2.h>#include<iphlpapi.h>#include<windows.h>#include<tlhelp32.h>#include<psapi.h>#include<ws2tcpip.h>#define _CRT_SECURE_NO_WARNINGS#pragma comment(lib, "iphlpapi.lib")#pragma comment(lib, "ws2_32.lib")#pragma comment(lib, "user32.lib")#pragma comment(lib, "advapi32.lib"// For UAC check and elevation// Function to check if an IP is public (exclude private/internal IPs)bool isPublicIP(const std::string& ip) {    // Split IP into 4 octets    unsigned int octet1, octet2, octet3, octet4;    if (sscanf_s(ip.c_str(), "%u.%u.%u.%u", &octet1, &octet2, &octet3, &octet4) != 4) {        return false; // Invalid IP format    }    // Exclude private IP ranges    if ((octet1 == 10) ||  // 10.0.0.0/8        (octet1 == 127) || // 127.0.0.0/8 (loopback)        (octet1 == 192 && octet2 == 168) || // 192.168.0.0/16        (octet1 == 172 && (octet2 >= 16 && octet2 <= 31)) || // 172.16.0.0/12        (octet1 == 0) ||  // 0.0.0.0 (invalid address)        (octet1 == 169 && octet2 == 254)) { // 169.254.0.0/16 (APIPA)        return false;    }    return true; // Public IP}// Function to get the process name given its PIDstd::wstring getProcessName(DWORD pid) {    wchar_t processName[MAX_PATH] = L"<未知>";    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);    if (hProcess != NULL) {        HMODULE hMod;        DWORD cbNeeded;        if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {            GetModuleBaseNameW(hProcess, hMod, processName, sizeof(processName) / sizeof(wchar_t));        }        CloseHandle(hProcess);    }    return std::wstring(processName);}// Function to get the process path given its PIDstd::wstring getProcessPath(DWORD pid) {    wchar_t processPath[MAX_PATH] = L"<未知>";    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);    if (hProcess != NULL) {        GetModuleFileNameExW(hProcess, NULL, processPath, sizeof(processPath) / sizeof(wchar_t));        CloseHandle(hProcess);    }    return std::wstring(processPath);}// Function to enumerate all network connectionsvoid enumerateConnections() {    PMIB_TCPTABLE2 tcpTable;    DWORD dwSize = 0;    DWORD dwRetVal = 0;    tcpTable = (MIB_TCPTABLE2*)malloc(sizeof(MIB_TCPTABLE2));    if (tcpTable == NULL) {        std::cerr << "分配内存时出错" << std::endl;        return;    }    dwSize = sizeof(MIB_TCPTABLE2);    if ((dwRetVal = GetTcpTable2(tcpTable, &dwSize, TRUE)) == ERROR_INSUFFICIENT_BUFFER) {        free(tcpTable);        tcpTable = (MIB_TCPTABLE2*)malloc(dwSize);        if (tcpTable == NULL) {            std::cerr << "分配内存时出错" << std::endl;            return;        }    }    if ((dwRetVal = GetTcpTable2(tcpTable, &dwSize, TRUE)) == NO_ERROR) {        char ipStringBuffer[INET_ADDRSTRLEN];        std::wstring output;        for (int i = 0; i < (int)tcpTable->dwNumEntries; i++) {            inet_ntop(AF_INET, &tcpTable->table[i].dwRemoteAddr, ipStringBuffer, INET_ADDRSTRLEN);            std::string remoteIp(ipStringBuffer);            // Filter out private/internal IPs            if (!isPublicIP(remoteIp)) {                continue; // Skip internal/private IPs            }            DWORD pid = tcpTable->table[i].dwOwningPid;            std::wstring processName = getProcessName(pid);            std::wstring processPath = getProcessPath(pid);            output += L"程序名称: " + processName + L"n连接的IP: " + std::wstring(remoteIp.begin(), remoteIp.end()) +                L"n程序路径: " + processPath + L"n---------------------------------n";        }        // Show the output in a message box        if (!output.empty()) {            MessageBoxW(NULL, output.c_str(), L"IP 和进程监控", MB_OK);        }        else {            MessageBoxW(NULL, L"未找到任何有效的公网连接信息。", L"IP 和进程监控", MB_OK);        }    }    else {        std::cerr << "GetTcpTable2 调用失败,错误代码: " << dwRetVal << std::endl;    }    if (tcpTable != NULL) {        free(tcpTable);        tcpTable = NULL;    }}// Function to check if the program is running as administratorbool isRunningAsAdmin() {    BOOL fIsRunAsAdmin = FALSE;    PSID pAdministratorsGroup = NULL;    SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;    if (AllocateAndInitializeSid(&NtAuthority, 2,        SECURITY_BUILTIN_DOMAIN_RID,        DOMAIN_ALIAS_RID_ADMINS,        0, 0, 0, 0, 0, 0,        &pAdministratorsGroup))    {        if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin)) {            fIsRunAsAdmin = FALSE;        }        FreeSid(pAdministratorsGroup);    }    return fIsRunAsAdmin;}// Function to restart the program with UAC elevationvoid runAsAdmin() {    wchar_t szPath[MAX_PATH];    if (GetModuleFileNameW(NULL, szPath, ARRAYSIZE(szPath))) {        SHELLEXECUTEINFOW sei = { sizeof(sei) };        sei.lpVerb = L"runas";        sei.lpFile = szPath;        sei.hwnd = NULL;        sei.nShow = SW_NORMAL;        if (!ShellExecuteExW(&sei)) {            DWORD dwError = GetLastError();            if (dwError == ERROR_CANCELLED) {                MessageBoxW(NULL, L"用户拒绝了权限提升请求。", L"错误", MB_OK);            }        }        else {            ExitProcess(0); // Terminate the current process since it's being restarted with elevation        }    }}int main() {    // Step 1: Check for administrator privileges    if (!isRunningAsAdmin()) {        MessageBoxW(NULL, L"尝试以管理员权限运行...", L"提示", MB_OK);        runAsAdmin();        return 0;    }    // Step 2: Enumerate all connections    enumerateConnections();    return 0;}
  1. 新增**isPublicIP**函数
    • 对 IP 地址进行解析,筛选出公网 IP。
    • 剔除内网范围(如127.0.0.0/8192.168.0.0/16172.16.0.0/12等)。
  2. **enumerateConnections**函数中调用**isPublicIP**
    • 遍历每个 TCP 连接时,使用isPublicIP检查远程 IP 地址,剔除内网 IP 和无效地址。
0x4 启动方面

1.启动目录及任务启动

#include <iostream>#include <string>#include <vector>#include <windows.h>#include <shlobj.h>#include <tlhelp32.h>#pragma comment(lib, "shell32.lib")std::vector<std::wstring> getFilesInDirectory(const std::wstring& directoryPath) {std::vector<std::wstring> filePaths;WIN32_FIND_DATA findFileData;HANDLE hFind = FindFirstFile((directoryPath + L"\*").c_str(), &findFileData);if (hFind == INVALID_HANDLE_VALUE) {return filePaths;    }do {conststd::wstring fileOrDirName = findFileData.cFileName;if (fileOrDirName != L"." && fileOrDirName != L"..") {conststd::wstring fullPath = directoryPath + L"\" + fileOrDirName;if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {                filePaths.push_back(fullPath);            }        }    } while (FindNextFile(hFind, &findFileData) != 0);FindClose(hFind);return filePaths;}voidshowMessage(const std::wstring& message) {MessageBoxW(NULL, message.c_str(), L"启动项检查"MB_OK | MB_ICONINFORMATION);}voidcheckStartupDirectories() {    wchar_t* userName = nullptr;    size_t len = 0;_wdupenv_s(&userName, &len, L"USERNAME");// 定义常见的启动目录    std::wstring startupDirectories[] = {        L"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup",        L"C:\Users\" + std::wstring(userName) + L"\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup",        L"C:\Users\" + std::wstring(userName) + L"\AppData\Local\Microsoft\Windows\Startup",        L"C:\Users\" + std::wstring(userName) + L"\AppData\Roaming\Microsoft\Windows\Startup"    };    free(userName);  // 释放分配的内存    std::wstring message = L"";    for (const auto& directory : startupDirectories) {        std::vector<std::wstring> files = getFilesInDirectory(directory);        if (!files.empty()) {            message += L"在目录 " + directory + L" 中找到以下启动项:n";            for (const auto& file : files) {                message += L"  - " + file + L"n";            }            message += L"n";        }    }    if (!message.empty()) {        showMessage(L"以下是各启动目录中的文件:n" + message);    } else {        showMessage(L"未检测到各启动目录中的启动项文件。");    }}void checkTaskSchedulerStartupItems() {    // 定义任务计划程序路径的查询命令    std::wstring command = L"schtasks /query /fo LIST /v";    std::wstring result = L"";    FILE* pipe = _wpopen(command.c_str(), L"r");    if (!pipe) {        showMessage(L"无法执行任务计划程序查询命令!");        return;    }    wchar_t buffer[1024];    while (fgetws(buffer, sizeof(buffer) / sizeof(wchar_t), pipe) != NULL) {        result += buffer;    }    _pclose(pipe);    if (!result.empty()) {        showMessage(L"任务计划启动项内容:n" + result);    } else {        showMessage(L"未检测到任务计划中的启动项。");    }}int main() {    checkStartupDirectories();    checkTaskSchedulerStartupItems();    return 0;}
(1)getFilesInDirectory()- 扫描目录中的文件
std::vector<std::wstring> getFilesInDirectory(const std::wstring& directoryPath){    std::vector<std::wstring> filePaths;    WIN32_FIND_DATA findFileData;    HANDLE hFind = FindFirstFile((directoryPath + L"\*").c_str(), &findFileData);if (hFind == INVALID_HANDLE_VALUE) {return filePaths;    }do {const std::wstring fileOrDirName = findFileData.cFileName;if (fileOrDirName != L"." && fileOrDirName != L"..") {const std::wstring fullPath = directoryPath + L"\" + fileOrDirName;if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {                filePaths.push_back(fullPath);            }        }    } while (FindNextFile(hFind, &findFileData) != 0);FindClose(hFind);return filePaths;}
  • 作用
    :获取指定目录中的所有文件路径。
  • 逻辑
    1. 调用FindFirstFile()FindNextFile()遍历目录。
    2. 忽略...(表示当前目录和父目录)。
    3. 只将非目录的文件路径加入结果列表。
  • 返回值
    :包含文件路径的std::vector
(2)checkStartupDirectories()- 检查常见启动目录
void checkStartupDirectories() {    wchar_t* userName = nullptr;    size_t len = 0;    _wdupenv_s(&userName, &len, L"USERNAME");    // 定义常见的启动目录    std::wstring startupDirectories[] = {        L"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup",        L"C:\Users\" + std::wstring(userName) + L"\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup",        L"C:\Users\" + std::wstring(userName) + L"\AppData\Local\Microsoft\Windows\Startup",        L"C:\Users\" + std::wstring(userName) + L"\AppData\Roaming\Microsoft\Windows\Startup"    };    free(userName);  // 释放分配的内存    std::wstring message = L"";for (const auto& directory : startupDirectories) {        std::vector<std::wstring> files = getFilesInDirectory(directory);if (!files.empty()) {            message += L"在目录 " + directory + L" 中找到以下启动项:n";for (const auto& file : files) {                message += L"  - " + file + L"n";            }            message += L"n";        }    }if (!message.empty()) {        showMessage(L"以下是各启动目录中的文件:n" + message);    } else {        showMessage(L"未检测到各启动目录中的启动项文件。");    }}
  • 作用
    :扫描系统中几个常见启动目录,列出其中的文件。
  • 步骤
    • 调用getFilesInDirectory()检查目录中的文件。
    • 如果存在文件,将其路径记录到消息内容中。
    • 公共启动目录:C:ProgramData...
    • 当前用户的启动目录:C:Users[USERNAME]AppData...
    1. 获取当前用户名(用于构造用户相关的目录路径)。
    2. 定义常见的启动目录路径数组,包括:
    3. 遍历每个目录:
    4. 弹窗显示结果。
  • 功能覆盖
    • 扫描所有用户级别和全局级别的启动目录。
(3)checkTaskSchedulerStartupItems()- 检查任务计划中的启动项
void checkTaskSchedulerStartupItems() {    // 定义任务计划程序路径的查询命令    std::wstring command = L"schtasks /query /fo LIST /v";    std::wstring result = L"";    FILE* pipe = _wpopen(command.c_str(), L"r");if (!pipe) {        showMessage(L"无法执行任务计划程序查询命令!");return;    }    wchar_t buffer[1024];while (fgetws(buffer, sizeof(buffer) / sizeof(wchar_t), pipe) != NULL) {        result += buffer;    }    _pclose(pipe);if (!result.empty()) {        showMessage(L"任务计划启动项内容:n" + result);    } else {        showMessage(L"未检测到任务计划中的启动项。");    }}
  • 作用
    :通过命令行工具schtasks获取任务计划中定义的启动项。
  • 步骤
    • /query
      :查询任务计划。
    • /fo LIST
      :输出为列表格式。
    • /v
      :显示详细信息。
    1. 定义命令:schtasks /query /fo LIST /v
    2. 使用_wpopen()打开命令行管道,执行命令。
    3. 读取命令输出,将其存储为字符串。
    4. 如果有输出,弹窗显示任务计划项的内容;否则提示没有启动项。
0x5 加上签名过滤
#include <iostream>#include <string>#include <vector>#include <windows.h>#include <tlhelp32.h>#include <psapi.h>#include <wintrust.h>#include <softpub.h>#include <winreg.h>#include <iphlpapi.h>#include <sddl.h>#include <fstream>#include <chrono>#include <thread>#include <Lmcons.h>#include <ShlObj.h>#include <ctime>#include <regex>#pragma comment(lib, "user32.lib")#pragma comment(lib, "advapi32.lib")#pragma comment(lib, "wintrust.lib")#pragma comment(lib, "iphlpapi.lib")#pragma comment(lib, "shell32.lib")std::vector<std::wstring> getFilesInDirectory(const std::wstring& directoryPath) {    std::vector<std::wstring> filePaths;    WIN32_FIND_DATA findFileData;    HANDLE hFind = FindFirstFile((directoryPath + L"\*").c_str(), &findFileData);if (hFind == INVALID_HANDLE_VALUE) {return filePaths;    }do {const std::wstring fileOrDirName = findFileData.cFileName;if (fileOrDirName != L"." && fileOrDirName != L"..") {const std::wstring fullPath = directoryPath + L"\" + fileOrDirName;if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {                filePaths.push_back(fullPath);            }        }    } while (FindNextFile(hFind, &findFileData) != 0);    FindClose(hFind);return filePaths;}bool isRunningAsAdmin() {    BOOL isAdmin = FALSE;    PSID adminGroup = NULL;    SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;if (AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,        DOMAIN_ALIAS_RID_ADMINS, 000000, &adminGroup)) {        CheckTokenMembership(NULL, adminGroup, &isAdmin);        FreeSid(adminGroup);    }return isAdmin;}void restartAsAdmin() {    wchar_t szPath[MAX_PATH];if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath))) {        SHELLEXECUTEINFO sei = { sizeof(sei) };        sei.lpVerb = L"runas";        sei.lpFile = szPath;        sei.hwnd = NULL;        sei.nShow = SW_NORMAL;if (!ShellExecuteEx(&sei)) {            std::cerr << "请求管理员权限失败。" << std::endl;            exit(EXIT_FAILURE);        }        exit(EXIT_SUCCESS);    }}std::wstring getProcessName(DWORD pid) {    wchar_t processName[MAX_PATH] = L"<未知>";    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);if (hProcess != NULL) {        HMODULE hMod;        DWORD cbNeeded;if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {            GetModuleBaseNameW(hProcess, hMod, processName, sizeof(processName) / sizeof(wchar_t));        }        CloseHandle(hProcess);    }return std::wstring(processName);}std::wstring getProcessPath(DWORD pid) {    wchar_t processPath[MAX_PATH] = L"<未知>";    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);if (hProcess != NULL) {        GetModuleFileNameExW(hProcess, NULL, processPath, sizeof(processPath) / sizeof(wchar_t));        CloseHandle(hProcess);    }return std::wstring(processPath);}bool isSystemProcess(HANDLE hProcess) {    HANDLE hToken = NULL;if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {returnfalse;    }    DWORD dwSize = 0;    GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize);    PTOKEN_USER pTokenUser = (PTOKEN_USER)malloc(dwSize);if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &dwSize)) {        free(pTokenUser);        CloseHandle(hToken);returnfalse;    }    WCHAR szName[MAX_PATH];    WCHAR szDomain[MAX_PATH];    DWORD dwNameSize = MAX_PATH;    DWORD dwDomainSize = MAX_PATH;    SID_NAME_USE sidType;if (LookupAccountSidW(NULL, pTokenUser->User.Sid, szName, &dwNameSize, szDomain, &dwDomainSize, &sidType)) {if (wcscmp(szName, L"SYSTEM") == 0) {            free(pTokenUser);            CloseHandle(hToken);returntrue;        }    }    free(pTokenUser);    CloseHandle(hToken);returnfalse;}std::vector<std::wstring> getExternalIPs(DWORD pid) {    std::vector<std::wstring> externalIPs;    PMIB_TCPTABLE2 tcpTable;    DWORD dwSize = 0;    GetTcpTable2(NULL, &dwSize, TRUE);    tcpTable = (PMIB_TCPTABLE2)malloc(dwSize);if (GetTcpTable2(tcpTable, &dwSize, TRUE) == NO_ERROR) {for (DWORD i = 0; i < tcpTable->dwNumEntries; i++) {if (tcpTable->table[i].dwOwningPid == pid) {                DWORD ipAddr = tcpTable->table[i].dwRemoteAddr;                BYTE* ipBytes = (BYTE*)&ipAddr;                std::wstring ipString = std::to_wstring(ipBytes[0]) + L"." +                    std::to_wstring(ipBytes[1]) + L"." +                    std::to_wstring(ipBytes[2]) + L"." +                    std::to_wstring(ipBytes[3]);if (!(ipBytes[0] == 192 && ipBytes[1] == 168) &&                    !(ipBytes[0] == 127 && ipBytes[1] == 0) &&                    !(ipAddr == 0)) {                    externalIPs.push_back(ipString);                }            }        }    }    free(tcpTable);return externalIPs;}enum ProcessSignatureStatus {    SIGNED_AND_TRUSTED,    SIGNED_BUT_NOT_TRUSTED,    NOT_SIGNED};ProcessSignatureStatus checkProcessSignature(const std::wstring& processPath) {    WINTRUST_FILE_INFO fileInfo = { 0 };    fileInfo.cbStruct = sizeof(fileInfo);    fileInfo.pcwszFilePath = processPath.c_str();    WINTRUST_DATA winTrustData = { 0 };    winTrustData.cbStruct = sizeof(winTrustData);    winTrustData.dwUIChoice = WTD_UI_NONE;    winTrustData.fdwRevocationChecks = WTD_REVOKE_NONE;    winTrustData.dwUnionChoice = WTD_CHOICE_FILE;    winTrustData.dwStateAction = WTD_STATEACTION_VERIFY;    winTrustData.pFile = &fileInfo;    GUID policyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;    LONG status = WinVerifyTrust(NULL, &policyGUID, &winTrustData);    winTrustData.dwStateAction = WTD_STATEACTION_CLOSE;    WinVerifyTrust(NULL, &policyGUID, &winTrustData);if (status == ERROR_SUCCESS) {return SIGNED_AND_TRUSTED;    }elseif (status == TRUST_E_NOSIGNATURE) {return NOT_SIGNED;    }else {return SIGNED_BUT_NOT_TRUSTED;    }}bool detectTrojanBehavior(DWORD pid, const std::wstring& processPath) {    bool hasSuspiciousBehavior = false;    std::vector<std::wstring> sensitiveDirs = { L"C:\Windows\System32", L"C:\Users" };for (const auto& dir : sensitiveDirs) {if (processPath.find(dir) != std::wstring::npos) {            hasSuspiciousBehavior = true;break;        }    }if (isSystemProcess(OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid))) {        hasSuspiciousBehavior = true;    }    HANDLE hProcessSnap;    PROCESSENTRY32 pe32;    pe32.dwSize = sizeof(PROCESSENTRY32);    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);if (hProcessSnap != INVALID_HANDLE_VALUE) {if (Process32First(hProcessSnap, &pe32)) {do {if (pe32.th32ProcessID != pid) {                    hasSuspiciousBehavior = true;break;                }            } while (Process32Next(hProcessSnap, &pe32));        }        CloseHandle(hProcessSnap);    }return hasSuspiciousBehavior;}bool isHighRiskProcess(const std::wstring& processName, const std::wstring& processPath) {    std::vector<std::wstring> keywords = { L"PC", L"财务", L"CW", L"2024", L"2023", L"工资", L"报表", L"调整" };    std::wregex extensionPattern(L".*\.(com|exe|bat)", std::regex_constants::icase);for (const auto& keyword : keywords) {if (processName.find(keyword) != std::wstring::npos && std::regex_match(processPath, extensionPattern)) {returntrue;        }    }returnfalse;}bool isProcessInAutostart(const std::wstring& processPath) {    HKEY hKey;    LPCWSTR runKeys[] = {        L"SOFTWARE\Microsoft\Windows\CurrentVersion\Run",        L"SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce",        L"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run",                L"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnce",        L"SYSTEM\CurrentControlSet\Services"    };for (int i = 0; i < sizeof(runKeys) / sizeof(runKeys[0]); i++) {if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, runKeys[i], 0, KEY_READ, &hKey) == ERROR_SUCCESS) {            DWORD index = 0;            wchar_t valueName[MAX_PATH];            wchar_t data[MAX_PATH];            DWORD valueNameSize = MAX_PATH;            DWORD dataSize = sizeof(data);while (RegEnumValue(hKey, index, valueName, &valueNameSize, NULL, NULL, (LPBYTE)data, &dataSize) == ERROR_SUCCESS) {                std::wstring dataStr(data);if (dataStr.find(processPath) != std::wstring::npos) {                    RegCloseKey(hKey);returntrue;                }                index++;                valueNameSize = MAX_PATH;                dataSize = sizeof(data);            }            RegCloseKey(hKey);        }    }returnfalse;}void showMessage(const std::wstring& message) {    MessageBoxW(NULL, message.c_str(), L"高危进程监控", MB_OK | MB_ICONINFORMATION);}void checkStartupDirectoriesForUnsignedFiles() {    wchar_t* userName = nullptr;    size_t len = 0;    _wdupenv_s(&userName, &len, L"USERNAME");    std::wstring startupDirectories[] = {        L"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup",        L"C:\Users\" + std::wstring(userName) + L"\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup"    };    free(userName);  // 记得释放内存    std::wstring message = L"";    for (const auto& directory : startupDirectories) {        std::vector<std::wstring> files = getFilesInDirectory(directory);        for (const auto& file : files) {            if (checkProcessSignature(file) == NOT_SIGNED) {                message += L"无签名文件: " + file + L"n";            }        }    }    if (!message.empty()) {        showMessage(L"检测到启动目录中存在以下无签名文件:n" + message);    }    else {        showMessage(L"未检测到启动目录中存在无签名文件。");    }}void monitorProcesses() {    HANDLE hProcessSnap;    PROCESSENTRY32 pe32;    pe32.dwSize = sizeof(PROCESSENTRY32);    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);    if (hProcessSnap == INVALID_HANDLE_VALUE) {        std::cerr << "创建进程快照失败。" << std::endl;        return;    }    if (!Process32First(hProcessSnap, &pe32)) {        std::cerr << "获取第一个进程失败。" << std::endl;        CloseHandle(hProcessSnap);        return;    }    std::wstring message = L"";    do {        DWORD pid = pe32.th32ProcessID;        if (pid == 0) continue;        HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);        if (hProcess == NULL) continue;        std::wstring processPath = getProcessPath(pid);        if (processPath.find(L"C:\Windows") != std::wstring::npos) {            CloseHandle(hProcess);            continue;        }        std::wstring processName = getProcessName(pid);        bool isHighRisk = isHighRiskProcess(processName, processPath);        ProcessSignatureStatus signatureStatus = checkProcessSignature(processPath);        if (signatureStatus == SIGNED_AND_TRUSTED) {            CloseHandle(hProcess);            continue;  // If the process is signed and trusted, skip it        }        std::vector<std::wstring> externalIPs = getExternalIPs(pid);        if (externalIPs.empty()) {            CloseHandle(hProcess);            continue;  // If there are no external IP connections, skip the process        }        bool hasSuspiciousBehavior = detectTrojanBehavior(pid, processPath);        bool inAutostart = isProcessInAutostart(processPath);        CloseHandle(hProcess);        std::wstring processInfo;        if (isHighRisk) {            processInfo = L"名称伪造高危进程: " + processName + L" (PID: " + std::to_wstring(pid) + L")n路径: " + processPath + L"n";        }        else if (signatureStatus == SIGNED_BUT_NOT_TRUSTED) {            processInfo = L"签名伪造高危进程: " + processName + L" (PID: " + std::to_wstring(pid) + L")n路径: " + processPath + L"n";        }        else if (signatureStatus == NOT_SIGNED) {            processInfo = L"无签名高危进程: " + processName + L" (PID: " + std::to_wstring(pid) + L")n路径: " + processPath + L"n";        }        else {            processInfo = L"进程: " + processName + L" (PID: " + std::to_wstring(pid) + L")n路径: " + processPath + L"n";        }        processInfo += L"  - 检测到外部IP连接:n";        for (const auto& ip : externalIPs) {            processInfo += L"    " + ip + L"n";        }        if (hasSuspiciousBehavior) {            processInfo += L"  - 检测到异常行为n";        }        if (inAutostart) {            processInfo += L"  - 已加启动n";        }        else {            processInfo += L"  - 未发现自启动n";        }        message += processInfo + L"n";    } while (Process32Next(hProcessSnap, &pe32));    CloseHandle(hProcessSnap);    if (!message.empty()) {        showMessage(message);    }    else {        showMessage(L"未检测到可疑进程。");    }}int main() {    if (!isRunningAsAdmin()) {        restartAsAdmin();    }    monitorProcesses();    checkStartupDirectoriesForUnsignedFiles();    return 0;}

原文始发于微信公众号(神农Sec):钓鱼 | 蓝队—反钓鱼的策略提供

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年1月5日22:43:55
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   钓鱼 | 蓝队—反钓鱼的策略提供https://cn-sec.com/archives/3593189.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息