先前因某原因进行研究Botnet,本文以僵尸网络BotenaGo中核心代码loader_multi.go为例,对源代码进行代码审计,梳理攻击逻辑。
概述
该框架源代码总共仅包含2891行代码(包括空行和注释)。
注释中提及包含反向shell加载程序和Telnet加载程序,可以根据攻击者的命令创建后门便于下一步攻击行动。
同时,框架包含以下EXP(见下图),其中存在部分CVE漏洞,可以凭借这些EXP针对不同设备或操作系统进行攻击。
另外,引用以下包在后续代码会使用到。
图1 包声明和注释
声明部分
声明包括常量、结构体、变量三个部分。
常量声明
首先是常量声明。
EI_NIDENT、EI_DATA、EE_LITTLE、EE_BIG分别为e_ident[]大小、数据编码、值为小端的EI_DATA标识、值为大端的EI_DATA标识。
EM_ARM、EM_MIPS、EM_AARCH64、EM_PPC、EM_PPC64、EM_SH分别为ELF头中所需运行架构为ARM框架的标识符、ELF头中所需运行架构为MIPS框架的标识符、ELF头中所需运行架构为AARCH64框架的标识符、ELF头中所需运行架构为PowerPC框架的标识符、ELF头中所需运行架构为PPC64框架的标识符、ELF头中所需运行架构为SH框架的标识符。
DVRIP_NORESP、DVRIP_OK、DVRIP_FAILED、DVRIP_UPGRADED为状态码的标识。
echoLineLen用于telnetLoadDroppers函数的dataBuf切片长度。
echoDlrOutFile用于telnetLoader函数的cat命令。
loaderTvtWebTag等Tag类常量用于构造EXP。
loaderDownloadServer、loaderBinsLocation、loaderScriptsLocation属于对C&C服务器的配置。
loaderDownloadServer为包含Bins和SH 文件的C&C服务器远程IP地址,loaderBinsLocation为Bins文件路径,loaderScriptsLocation为SH 文件路径。
图2 常量声明
结构体声明
elfHeader 文件格式头结构体,e_ident[EI_NIDENT]即Magic Number,e_type为类型。
e_machine为运行该程序需要的体系结构,e_version为文件版本。
smapsRegion结构体,成员region用于标识smaps内存所属区域,成员size为进程使用内存空间,rss为int型,pss为Rss中私有的内存页面,成员shared_clean,shared_dirty,private_clean,private_dirty分别为Rss中和其他进程共享的未改写页面、Rss和其他进程共享的已改写页面、Rss中改写的私有页面页面、 Rss中已改写的私有页面页面。
echoDropper结构体用于木马相关的变量使用,成员payload与payload_count。
图3 结构体声明
变量声明
声明了一个time包中的time.Duration类型变量,初始值为30。
声明了两个WaitGroup变量workerGroup、magicGroup。
两个string类型变量mode、doExploit。
集合exploitMap、dropperMap,前者为EXP集合、后者为木马集合。
变量telShells和payloadSent用作计数器,分别为telnet连接的shell数量和发送的payload数量。
后面为各设备的EXP和攻击设置的构造部分。分别为uc、tvt、magic、lilindvr、烽火通信设备、vigor VPN设备、broadcom路由器、宏电IOT设备、Tenda路由器、totlink路由器、zyxel NAS 系统、Alcatel NAS系统、linksys路由器、中兴路由器、NETGEAR路由器、GPON路由器、D-Link路由器。
图4 变量声明1
图5 变量声明2
函数
函数zeroByte
生成字节”0“。函数getStringInBetween获取字符串内容。函数randstr从大小写A到Z中选取生成随机字符串。函数hexToint将hex码转换成int型。
图6 函数1
telnet加载程序模块
telnetLoadDroppers函数
telnetLoadDroppers函数用于Droppers加载部分,遍历路径下文件并读取。
首先短声明变量files,err,值为OpenFile函数的结果,参数分别为打开文件的文件路径、flag、权限码。之后异常处理,如果error就执行continue。声明结构体变量mapval为结构体echoDropper的变量。其中的成员payload_count赋值为0。
循环结构首先声明string型变量echoString,声明databuf按照128字节的byte型数组。声明length,err,值为Read函数的结果,参数为databuf。异常处理:如果error或者length异常,break跳出循环。
循环处理声明echoByte,值为以dataBuf为输入按照x%02x格式化处理,并且以uint8类型输出。echoString每次填充echoByte。如果payload_count为0,则打印首次输出命令行;如果payload_count不为0,则打印后续输出命令行。最后按照循环次数依次增加payload_count计数器。
回到函数部分,逐次获取文件名执行处理。然后关闭文件流。打印telnetLoadDroppers函数执行结果。
telnetHasPrompt函数
telnetHasPrompt函数用于判断是否包含特殊符号。首先将string类型的buffer作为参数,使用Contains函数进行判断。如果buffer中包含”#”、”>”、”$”、”%”、”@”这些特殊符号其中一种,则返回true;如果都不包含,则返回false。
telnetBusyboxShell函数
telnetBusyboxShell函数用于调用busybox中相关命令于该攻击框架。
注:BusyBox 是一个集成了三百多个最常用Linux命令和工具的软件。BusyBox 称为 Linux 工具里的瑞士军刀。
其中前三句命令推测用于部分BCM路由器。因为第一句 conn.Write([]byte(“shrn”)) 在后续再次出现。
可以看到攻击常用的命令,例如sh,ping,system等等。
infectFunctionComtrend函数
infectFuctionTenda函数用于Comtrend路由器。
根据函数内容判断,EXP为CVE-2020-10173(Comtrend VR-3033 路由器多认证命令注入漏洞)
infectFuctionTenda函数
infectFuctionTenda函数用于Tenda路由器。
根据函数内容判断,EXP为CVE-2020-10987(Tenda AC系列路由器远程命令执行0day漏洞)。
声明一个rdbuf数组,类型为byte。
Main函数
01
一个循环结构执行显示当前加载程序结果。
02
定义dropperMap,分片从echoDropper获取。
03
调用telnetLoadDroppers函数、scannerInitExploits函数。
04
声明li、err,调用net包的Listen声明,根据TCP协议配置监听设置,根据ucRshellPort作为监听端口。recvServ、err,调用net包的Listen,根据TCP协议在本地接收监听的流量,用19412端口接收。
05
循环执行reverseShellUchttpdLoader函数,参数是conn,直到err != nil。根据缓冲区循环执行httpBannerCheck函数,参数是buf,直到err != nil。
06
循环结构。声明reader、input变量,分别为以os.Stdin为参数调用bufio包的NewReader,以reader为参数调用bufio包的NewScanner。
结束语
本文为僵尸网络BotenaGo的代码审计文章,将核心代码loader_multi.go进行了前期分析,预计不定期会跟进,梳理成后续文章。
往期推荐
火线Zone是火线安全平台运营的安全社区,拥有超过20,000名可信白帽安全专家,内容涵盖渗透测试、红蓝对抗、漏洞分析、代码审计、漏洞复现等热门主题,旨在研究讨论实战攻防技术,助力社区安全专家技术成长,2年内已贡献1300+原创攻防内容,提交了100,000+原创安全漏洞。
欢迎具备分享和探索精神的你加入火线Zone社区,一起分享技术干货,共建一个有技术氛围的优质安全社区!
原文始发于微信公众号(火线Zone):Botnet BotenaGo代码审计浅析(一)