于我

Rust C2框架LINK分析

2022/7/27
01 前言

近年来,Rust语言开始受到恶意软件开发者的青睐,不同的恶意软件家族已经使用Rust语言来重构恶意软件,例如Buer家族银行木马,BlackCat和Hive家族勒索等。Rust受到恶意软件开发者的青睐可能有开发效率,性能,内存安全等方面的因素,但最重要的使用rust编译出来的恶意软件会更容易逃避终端安全软件的静态检测。

可以预知,未来使用Rust编写的恶意软件将会越来越多,想要更好的应对这些未知威胁,我们必须做到知己知彼,才能在这场无硝烟的战争中不落下风。

为了快速熟悉Rust在编写恶意软件中的手法,我这里选择的是开源红队C2框架Link进行分析。

02 介绍

Link是基于Rust语言开发的跨平台C2框架,支持HTTPS协议监听,在技术点上实现了sRDI,内存注入,逃避检测等功能,是一个小而美的C2框架。

源码地址:https://github.com/postrequest/link

03 使用

作者已经提供了kali安装的脚本,在安装过程中会安装rust编译环境和编译依赖,并配置编译生成可执行文件。

3.1主菜单

运行编译好的link,开启https监听,help命令查看主菜单

这里主要关注三个命令即可

generate

生成不同平台的后门

generate(generate,generate-linux,generate-osx)

Use: generate ip/domain:port

sharp

下载https://github.com/Flangvik/SharpCollection工具包后续使用

links

会话展示

3.2 会话功能

links -i id进入当前会话

可根据命令执行具体操作

04 源码分析

工程源码布局

4.1通信

控制端和implant之间一共通过三种请求实现整体的上线和任务收发

Get请求: https://{}/js

Post请求: https://{}/static/register

Post请求: https://{}/static/get

控制端

在spawn.rs中的spawn_server函数中创建线程开启https监听

开启https监听时配置路由,控制端收到请求具体的处理如下

implant

implant向控制端发的请求很简单,分为三个过程

建立通信

首先尝试发送get请求和服务器建立连接当发送的请求得到服务器的回应,发送上线包

上线数据

获取用户名,主机名,ip,外网ip(未实现),平台类型,进程pid,将数据json处理后通过post请求发送到服务器,服务器确认上线后会返回一个请求id(x_request_id)

任务接收

在请求头中加入请求idimplant每次请求服务端都会发一个新的请求id,用于implant下次请求封装的任务数据

HTTP数据流

为了更清晰地看到客户端和服务端的通信,去除代码中的ssl加密,转换成http监听,使用wireshark抓包查看http流数据从建立连接到查询任务

当控制端下发任务

4.2 implant功能

在implant中,除windows外,link对其他平台只实现了shell等几个简单的功能,因此这里只分析windows下的implant

逃避检测

windows implant在启动时会重新映射kernel32.dll和ntdll.dll的.text段,以防止终端安全软件通过注库进行hook,部分代码片段如下

内存dump

Link用的内存dump是用rust重新实现的,在in_memory_dump函数中,利用NtGetNextProcess函数获取要dump的进程句柄,然后使用MiniDumpWriteDump函数进行dump

执行shellcode

创建进程通过APC注入shellcode

进程注入

创建远程线程注入shellcode

4.3控制端功能

控制端的主要功能都和生成shellcode有关

下发任务时使用donut生成shellcode传给implant加载执行

生成implant时使用sRDI生成shellcode形式的implant

donut

调用donut生成shellcode代码

sRDI

link将sRDI中的代码用rust实现,能够将dll以shellcode的形式实现反射dll注入。link sRDI的shellcode构成:bootstrap(保存dll信息的shellcode) + rdiShellcode(反射dll注入shellcode) + dllBytes(原始dll数据) + userData(标志)

(这里以64位为例进行分析)

保存dll信息的shellcode

第一段shellcode长度很短,主要是保存dll的一些信息

结合代码去看逻辑很清晰

反射dll注入shellcode

这里link中的这段shellcode生成的代码比sRDI的shellcode短了不少,应该是对sRDI的代码经过精简的,不过原理都是PE加载,大致流程都是通过PEB获取所需函数->为要加载的dll分配内存->拷贝PE头部和区段(内存对齐粒度)->修复IAT->修复重定位->调用入口点->调用导出函数(这段shellcode对PE加载处理的更细致,也考虑了TLS和注册异常处理等)

通过PEB获取所需函数,shellcode中hash对应的函数

对PE文件做校验

循环获取每个区段的虚拟地址和文件对齐长度

根据sizeofheaders向新申请的内存空间复制DOS头(根据flags只保留e_lfanew)+NT头+区段头

循环复制区段

修复IAT

修复重定位并更新重定位后的代码

调用入口点完成加载并调用dll导出函数main

05 总结

Link可以称得上是麻雀虽小五脏俱全,整体上有很多值得学习的地方。在分析Link的过程中,不仅看到了Rust第三方包obfstr混淆字符串的便携强大,也感受到了逆向Rust代码的痛苦,现有IDA等反编译工具对Rust二进制元数据解析支持做的不够,导致大部分用户代码逻辑都被堆叠在一起,函数边界不清晰,看起来十分混乱,在面对杀软检测和逆向分析时具有天然对抗优势。

Rust恶意软件是一个新威胁,新挑战。在这场较量中,作为安全人员的我们没有理由让步,现在要做的就是时刻准备,等待接招。

上一篇:【漏洞分析】VMware CVE-2022-22972 身份认证绕过漏洞
下一篇:【漏洞分析】CVE-2022-35405 漏洞分析

开始免费试用灰度产品

申请试用