上周看了盘古实验室发表的《Bvp47 美国NSA方程式的顶级后门》的文章,里面提到后门使用BPF技术做通信信道的隐藏,本身不监听端口,通过特定SYN包唤醒后门。而且,此后门隐藏近二十年之久,至今才被发现。
Bvp47 直接利用 BPF 的这个特性作为隐蔽信道环节中在 Linux 内核层面的高级技巧,避免直接的 内核网络协议栈HOOK被追踪者检测出来。
具体的 BPF 汇编如下,只有满足这部分规则的 SYN 数据包(还包括UDP包)才会进入下一个加解密 流程进行处理:
文中一句带过,没有过多的细节描述。也能理解,毕竟是逆向黑盒分析,没有源码,还是有一些吃力。
恰巧笔者近期在学习eBPF,且在春节前用eBPF技术实现了类似功能的后门DEMO,对这块特别感兴趣。 好奇它的兼容性是如何做的,HOOK点是如何选择的?用的BPF/eBPF哪个内核版本的类库?
演示DEMO的后门,绕过了服务器内的多款防御产品。
之前的演示视频做的比较潦草,缺少相关技术原理图,不太好理解,不推荐看了。新的视频已经剪辑好,近期笔者会在文章里分享。
当然,笔者是为了网络安全的红蓝对抗,才写的后门恶意利用的DEMO,用于作为HIDS等防御产品规划的论据,也是提醒同行需要对eBPF技术的恶意利用多加防范。
好奇之下,笔者根据自己eBPF网络信道隐藏的DEMO实现,猜测了一下Bvp47的隐藏原理。
从PDF里的汇编图来看,后门使用的是BPF技术,不是eBPF。且受影响版本都是linux 内核为2.6系列。
回顾BPF发展历程:
文中提到受影响内核是2.6.x, 那使用的BPF版本还比较老,只能过滤网络流量。
理论是跟eBPF类似,大约在XDP层附近,工作在网卡驱动附近,可以做流量过滤处理,之后再交付给内核的网络协议相关函数。 libpcap
的原理是包的clone,再传递,本身不影响应用层拿到原始包。在这个后门里做敲门的功能是足够了。至于传过去的自定义格式SYN
标志包,应用层能否解析,影响也不大,也很难会被发现。
但如果是eBPF里,可以在XDP层读取、修改、丢弃包,TCP栈这层都拿不到包,更不用说应用层了,可以隐藏的更深。
普通内核网络部分函数HOOK的话,大约在网络层那块。所以,能很好的隐藏入口流量。 补个eBPF
的图,方便大家理解。虽然后门用的是BPF技术,
Packet flow in Netfilter and General Networking图出自: https://commons.wikimedia.org/wiki/File:Netfilter-packet-flow.svg ,做网络相关工作的运维SRE、研发工程师、安全工程师建议收藏。
怀着好奇的心理,笔者在国外的安全网站找到了这个后门原型 ,在2002年,有安全网站分享出来了。
cd00r.c is a proof of concept code to test the idea of a completely invisible (read: not listening) backdoor server. Standard backdoors and remote access services have one major problem – the port’s they are listening on are visible on the system console as well as from outside (by port scanning). To activate the remote access service, one has to send several packets (TCP SYN) to ports on the target system. Which ports in which order and how many of them can be defined in the source code.
涉及BPF的核心代码如下:
/* variables for the pcap functions */
#define CDR_BPF_PORT "port "
#define CDR_BPF_ORCON " or "
char pcap_err[PCAP_ERRBUF_SIZE]; /* buffer for pcap errors */
pcap_t *cap; /* capture handler */
bpf_u_int32 network,netmask;
struct pcap_pkthdr *phead;
struct bpf_program cfilter; /* the compiled filter */
struct iphdr *ip;
struct tcphdr *tcp;
u_char *pdata;
...
if (cports[0]) {
memset(&portnum,0,6);
sprintf(portnum,"%d",cports[0]);
filter=(char *)smalloc(strlen(CDR_BPF_PORT)+strlen(portnum)+1);
strcpy(filter,CDR_BPF_PORT);
strcat(filter,portnum);
} else {
if (cdr_noise)
fprintf(stderr,"NO port code\n");
exit (0);
}
/* here, all other ports will be added to the filter string which reads
* like this:
* port <1> or port <2> or port <3> ...
* see tcpdump(1)
*/
for (i=1;i<cportcnt;i++) {
if (cports[i]) {
memset(&portnum,0,6);
sprintf(portnum,"%d",cports[i]);
if ((filter=(char *)realloc(filter,
strlen(filter)+
strlen(CDR_BPF_PORT)+
strlen(portnum)+
strlen(CDR_BPF_ORCON)+1))
==NULL) {
if (cdr_noise)
fprintf(stderr,"realloc() failed\n");
exit (0);
}
strcat(filter,CDR_BPF_ORCON);
strcat(filter,CDR_BPF_PORT);
strcat(filter,portnum);
}
后门的全部代码,笔者放在了github上:https://github.com/ehids/rootkit-sample/blob/master/cd00r.c 。
同时,笔者还找到了二十多年前,GIAC公司对这款后门的分析预警,笔者也放在上面的git仓库里了。
后门原型的代码比较少,读起来也不复杂。核心实现是调用libpcap类库进行网络包的过滤读取,识别每个TCP包中SYN
标识位的body部分内容,找到相关特征进行匹配验证,验证通过,则启动后门连接进程,开启端口监听。 这后门默认不监听端口,会读取主机所有流量过滤,找到secret knock
密码特征后,再执行入侵者预留的后门代码。
cd00r后门在过滤数据包时,筛选了常用的200
、80
、22
、53
、3
等端口,再启动inetd
等进程,监听5002/tcp
端口,让这个进程与入侵者交互。真正的交互后门进程,是通过secret knock
特征敲门后启动,还是有一些隐蔽性。并且,这个后门敲门后执行cdr_open_door()
函数,启动的是inetd
进程,实际上可以修改为其他任意代码。
整个流程如下:
secret knock
敲门端口等secret knock
密码匹配,不匹配则跳过secret knock
密码匹配,则执行入侵者的代码,比如执行inetd
进程。从代码来看,流程、逻辑都比较清晰,不是很复杂。从后门构思上来看,比较巧妙。若是现在的环境,有eBPF支持下,那会更加可怕。可以参考笔者的eBPF恶意利用
相关视频。
回到主题上,根据盘古的PDF报告,Bvp47
后门是2002年,cd00r
是在2000年,相信Bvp后门的设计也参考了cd00r
的灵感,在此基础上做了很多演进与扩展。
Bvp47后门使用的应该是最初版本的BPF指令,而且应该不是直接使用,而是引用了libpcap
类库间接用了BPF指令。 在SYNKnock
敲门机制上,应该与cd00r
一致,这也能从PDF的截图里看到。 敲门后,才启动控制端,监听端口。
在PDF里有很详细的描述,原理是通过SYN包附带payload,来逃避常规软件的检测。并对payload做了加密。
后门的SYNKnock
敲门机制依赖libpcap做网卡嗅探,依赖BPF指令做网络包过滤。这些类库与BPF指令有着系统版本的限制,Bvp47后门用的是linux kernel 2.6内核的BPF版本,只能在2.6版本的内核上运行。这也是这篇PDF里展示受害系统都是2.6的原因。
若后门考虑兼容性,那么必定会根据不同版本分别做代码兼容编写、编译、分发才能做到。
在2022年,eBPF有了BTF规范的加持,CO-RE特性有着更好的系统兼容性,在为应用程序提供更便捷的维护成本外,也给木马后门带来了便捷。
后门在SYNKnock
敲门上做了隐藏,不需要监听端口就可以发起指令。在后续的通讯交互中,会启动新的进程。 新的进程内会包含大量用户态的行为,产生各种日志。防御方还是有一定痕迹可循。
话说回来,这是二十年前的后门技术,隐藏信道部分
从技术原理上来看,并不复杂,只是没有被大家重视。
而且,这后门只是在端口监听上,敲门阶段没有监听端口,在后门的连接、信息传输阶段,还是开了端口的。 在后门账号上,采用写入系统用户名、密码的方式,来实现SSHD的认证存储,本身还是有/etc/passwd
等文件读写的用户态行为,现有HIDS都具备发现的能力。
但是,这是二十年前的技术,如今,BPF已经演进为eBPF,其功能更是强大,覆盖范围不止网络控制,还包括内核态函数、用户态函数、跟踪点、性能事件、安全控制等。 笔者演示的两个基于eBPF的后门行为来看,可以做的更加隐蔽,不产生用户态行为,更加可怕,给防御方的挑战也越来越大。
随着云原生场景迅速发展,eBPF技术的后门场景也越来越多,你的服务器上,是不是已经有这种后门在运行了?这种类型的安全产品该如何检测防御呢?
笔者整理了一篇《Linux中基于eBPF的恶意利用与检测机制》,近期分享给大家,请关注榫峁江湖
微信公众号。
CFC4N的博客 由 CFC4N 创作,采用 知识共享 署名-非商业性使用-相同方式共享(3.0未本地化版本)许可协议进行许可。基于https://www.cnxct.com上的作品创作。转载请注明转自:聊一聊《Bvp47 美国NSA方程式的顶级后门》中的BPF隐藏信道