您当前的位置:首页 > 电脑百科 > 安全防护 > 服务器/网站

在Netty服务被N次攻击之后,终于抓到现行了

时间:2021-02-05 09:56:05  来源:  作者:

原文出自:公众号 程序新视界

原文作者:https://mp.weixin.qq.com/s/GzvwZvVNHx4yjEUVibSNBA

前言

马上就要过春节了,本想着完成手头的任务就可以准备过年了。没想到Netty服务器又被攻击了,当收到服务器报警(CPU飙升报警)信息,就知道对方又下手了。

之前是交给下面的兄弟来解决,这次为了过个好年,决定亲自动手把这事给了结了。

故事前奏

Netty服务是公司比较边缘的服务,只有一台设备在使用,而且代码是之前技术Leader(已离职)写的,加上一直赶工期,所以就没抽出时间去彻底解决这事。

当初被攻击没排查代码,看到遭到疯狂请求、CPU跑满、日志打满,还以为是遭遇DDoS攻击了。

临时采取了几个措施:

  • 分离服务器,确保该服务遭到攻击时不会拖垮其他服务;
  • 换了一个IP和端口;
  • 针对攻击的IP添加黑名单;
  • 在代码层,发现非法请求强制关闭连接;
  • 添加日志信息,追溯攻击报文和源头;
  • 对攻击服务的IP(上海阿里云的)进行举报;

但没多久,黑客又找上门来了,十天半月来一次攻击,好像知道服务IP和后台代码似的,阴魂不散。

这不,今天被逮到了,而且之前添加了日志打印,也拿到了攻击的报文内容,复现了攻击操作。

// 攻击者第一次尝试的报文
8000002872FE1D130000000000000002000186A00001977C0000000000000000000000000000000000000000
// 攻击者第二次尝试的报文
8000002872FE1D130000000000000002000186A00001977C00000000000000000000000000000000

上述报文,第一次的报文触发了攻击,第二次的报文没有影响(与正常业务报文格式无异)。

下面就带大家分析分析攻击的逻辑和代码中存在的漏洞。

知识储备

要了解攻击的原理,我们需要有一定的Netty技术知识。关于Netty如何实现客户端和服务器端的代码这里就不展开了,可以看一下实现实例:https://github.com/secbr/netty-all/tree/main/netty-decoder

我们重点了解一下自定义解码器和io.netty.buffer.ByteBuf。其中自定义解码器用于对报文进行解析,而报文内容通过ByteBuf进行缓存传输。

上面的攻击报文格式表明,黑客已经“猜到”我们是基于16进制Btye格式进行内容传输的(黑客竟然也知道)。

自定义解码器

要自定义解码器,继承MessageToMessageDecoder类并实现decode方法即可,下面展示一下示例代码:

public class MyDecoder extends MessageToMessageDecoder<ByteBuf> {

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
    }
}

其中解析报文的逻辑便是在decode方法内进行处理。其中ByteBuf in就是接收传入报文的容器,而List<Object> out用于输出解析之后的结果。

下面来看一下有bug的代码(已经过脱敏处理):

protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
    int readableBytes = in.readableBytes();
    while (readableBytes > 3) {
        in.skipBytes(2);
        int pkgLength = in.readUnsignedShort();
        in.readerIndex(in.readerIndex() - 4);
        if (in.readableBytes() < pkgLength) {
            return;
        }
        out.add(in.readBytes(pkgLength));
        readableBytes = in.readableBytes();
    }
}

上面的代码在跑正常业务时是没问题的,但当被攻击时,就进入了死循环。因此,导致虽然在业务处理时添加了关闭连接的操作也是无效的。

在分析上面代码之前,我们还得先详细分析一下ByteBuf的原理。

ByteBuf的原理

ByteBuf中会维护两个索引:一个索引(readIndex)用于读取,一个索引(writeIndex)用于写入。

当从ByteBuf读取时,readIndex会被递增已经被读取的字节数,当向ByteBuf中写入数据时,writeIndex也会被递增。

在Netty服务被N次攻击之后,终于抓到现行了

 

上面图以攻击的报文为例进行展示,攻击者用了44个字节的报文进行攻击。由于使用的是16进制,所以两个字符占用1个字节。

readIndex和writeIndex的起始位置的索引位置都为0,当执行ByteBuf中的readXXX或writeXXX方法时,会推进对应的索引。当执行setXXX或getXXX方法的操作时则不会。

了解了ByteBuf的基本处理原理之后,我们就来对照攻击者的报文和源代码来进行攻击过程的还原。

攻击还原

下面直接通过源代码一步步的分析,主要涉及ByteBuf类的方法。有效攻击的报文为上面提到的第一个报文。

// 攻击者第一次尝试的报文
8000002872FE1D130000000000000002000186A00001977C0000000000000000000000000000000000000000

下面来看代码:

int readableBytes = in.readableBytes();

这行代码通过readableBytes方法获取到当前ByteBuf中可以读到的字节数,上述攻击报文88个字符,所以这里得到44个字节。

当readableBytes大于3时便进行具体的解析处理:

in.skipBytes(2);

很明显,通过skipBytes方法跳过了两个字节。

在Netty服务被N次攻击之后,终于抓到现行了

 

int pkgLength = in.readUnsignedShort();

通过readUnsignedShort方法,获得了2个字节的内容,这两个字节对应的十六进制值为“0028”,对应十进制为“40”。这两个字节在报文中的含义是(部分或整个)报文的长度。

报文的长度往往有两种算法:第一,长度代表整个报文的长度(业务中使用的含义);第二,长度代表除前4个字节之后的报文长度(攻击者使用的含义)。

其实,正是因为这个长度含义的定义,导致正常业务可以执行,而攻击报文会进入死循环。

下面继续分享代码:

in.readerIndex(in.readerIndex() - 4);

经上面的skipBytes和readUnsignedShort的调用,ByteBuf的读索引已经跑到了第4个字节上了。所以这里in.readerIndex()返回的值为4,而in.readerIndex(4-4)的作用就是将读索引重置为0,也就是从头开始读。

if (in.readableBytes() < pkgLength) {
    return;
}

这个判断是在读索引移动到0之后,看看报文的可读字节数是否小于报文内容中指定的字节数。很显然,in.readableBytes()对应的值为44个字节,而pkgLength为40个字节,不会进行return。

out.add(in.readBytes(pkgLength));

读取40个字节,进行输出。还剩下4个字节的内容,readIndex指向第40个字节的位置。

readableBytes = in.readableBytes();

由于readIndex已经指向第40个字节,所以此时可读字节数为4。

然后,进入第二轮循环。此时,神奇的情况就出现了。我们可以看到攻击的后4个字节的报文值全为0。

in.skipBytes(2);
int pkgLength = in.readUnsignedShort();

因此跳过2个字节后,readIndex为42,pkgLength获取第43和44字节的值:0。

in.readerIndex(in.readerIndex() - 4);

上述代码又将readIndex设置到第40个字节。

if (in.readableBytes() < pkgLength) {
    return;
}

此时会发现readableBytes返回值为4,但pkgLength已经变为0了,不会return。

接下读取内容时就出现状况了:

out.add(in.readBytes(pkgLength));
// 这里还剩下4个字节
readableBytes = in.readableBytes();

上述readBytes读取字节数为0,而readableBytes始终为4。此时,整个while循环进入了死循环,大量消耗CPU资源。

此时还没完,最多只是把CPU跑到100%,但是当不停的将空字符写到接收数据的缓冲区域之后,缓冲区开始疯狂调用处理业务的Handler,进一步侵入到业务处理逻辑当中。

虽然业务逻辑层做了判断,也进行了连接的关闭,但此时已经与连接无关,while循环已经进入死循环,关掉连接也没什么作用。同时,业务层有日志输出,大量的日志输出到磁盘当中,导致磁盘被刷满。

最终导致服务器的CPU监控和磁盘监控报警。乍一看,还以为是又一次DDoS攻击……

小结

总结一下,其实就是攻击者传输的报文长度和报文内指定的长度不一致,导致了解析报文时进入了死循环。

问题一旦发现,解决起来就很容易了。其实通过这件事也得到一些启发。第一,遇到问题,迎难而上解决掉它,往往是最好的方案,逃避只能将问题往后拖,但并不能解决掉。第二,只要静下心来分析,一步步分析,很少有解决不掉的问题。



Tags:Netty   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
前言在实现TCP长连接功能中,客户端断线重连是一个很常见的问题,当我们使用netty实现断线重连时,是否考虑过如下几个问题: 如何监听到客户端和服务端连接断开 ? 如何实现断线后重...【详细内容】
2021-12-24  Tags: Netty  点击:(12)  评论:(0)  加入收藏
这篇文章对于排查使用了 netty 引发的堆外内存泄露问题,有一定的通用性,希望对你有所启发 背景最近在做一个基于 websocket 的长连中间件,服务端使用实现了 socket.io 协议(基于...【详细内容】
2021-12-16  Tags: Netty  点击:(22)  评论:(0)  加入收藏
简介在之前的文章中,我们提到了在netty的客户端通过使用Http2FrameCodec和Http2MultiplexHandler可以支持多路复用,也就是说在一个连接的channel基础上创建多个子channel,通过...【详细内容】
2021-12-14  Tags: Netty  点击:(6)  评论:(0)  加入收藏
本系列为 Netty 学习笔记,本篇介绍总结Java NIO 网络编程。Netty 作为一个异步的、事件驱动的网络应用程序框架,也是基于NIO的客户、服务器端的编程框架。其对 Java NIO 底层...【详细内容】
2021-12-07  Tags: Netty  点击:(16)  评论:(0)  加入收藏
想要阅读Netty源码的同学,建议从GitHub上把源码拉下来,方便写注释、Debug调试哦~点我去下载! 先来看一个简单的Echo服务端程序,监听本地的9999端口,有客户端接入时控制台输出一句...【详细内容】
2021-10-22  Tags: Netty  点击:(43)  评论:(0)  加入收藏
相信很多人知道石中剑这个典故,在此典故中,天命注定的亚瑟很容易的就拔出了这把石中剑,但是由于资历不被其他人认可,所以他颇费了一番周折才成为了真正意义上的英格兰全境之王,亚...【详细内容】
2021-07-22  Tags: Netty  点击:(102)  评论:(0)  加入收藏
家纯 阿里技术 一 什么是 Netty? 能做什么? Netty 是一个致力于创建高性能网络应用程序的成熟的 IO 框架。 相比较与直接使用底层的 Java IO API,你不需要先成为网络专家就...【详细内容】
2021-06-23  Tags: Netty  点击:(136)  评论:(0)  加入收藏
客户端代码package com.huanfeng.test;import java.io.BufferedReader;import java.io.InputStreamReader;import java.net.URL;import java.net.URLConnection;import java...【详细内容】
2021-05-26  Tags: Netty  点击:(145)  评论:(0)  加入收藏
前言:作为一个刚踏入职场的实习生,我很幸运参加了某个政府项目,并且在项目中负责一个核心模块功能的开发,而不是从头到尾对数据库的crud。虽然我一直心里抱怨我的工作范围根本...【详细内容】
2021-05-24  Tags: Netty  点击:(230)  评论:(0)  加入收藏
要求1.群聊系统可以实现服务器端和客户端之间的数据简单通讯(非阻塞)2.通过系统可以实现多人群聊3.服务器端:可以监控用户上线,离线,并实现消息转发功能4.客户端:通过channel可...【详细内容】
2021-05-24  Tags: Netty  点击:(147)  评论:(0)  加入收藏
▌简易百科推荐
在最近的一波攻击中,黑客利用多个插件中未修补的漏洞攻击了 160 万个 WordPress 网站。 易受攻击的插件对 WordPress 网站产生了的巨大攻击数据。 Wordfence 最近发现 WordPr...【详细内容】
2021-12-16  蚁安    Tags:WordPress   点击:(8)  评论:(0)  加入收藏
事件起因从安全分析系统里面发现一条带有病毒的下载,然后针对这条记录展开了一系列的分析分析过程1.登录到被感染服务器,查看系统状况,hadoop 这个用户在 2020/6/18 20:32 从这...【详细内容】
2021-11-23  Z2990Lig    Tags:SSH   点击:(32)  评论:(0)  加入收藏
1、除了服务器需要用的一些正规软件,其它都不要安装。2、在用户中把administrator改名,这样做的目的是即使对方暴破了我们的密码用户名也不容易猜住,相当于又加了一道关卡。...【详细内容】
2021-11-01  IT小哥吧    Tags:服务器   点击:(37)  评论:(0)  加入收藏
账户安全(1)更名administrator本地用户并禁用guest账户步骤:点击“开始”,找到“管理工具”,点击里面的“计算机管理”,找到“本地用户和组” (2)设定账户锁定策略尝试5次失败...【详细内容】
2021-10-12  Kali与编程  今日头条  Tags:Windows主机   点击:(62)  评论:(0)  加入收藏
本文主要介绍以Microsoft的Windows Server 2019 ,版本:Datacenter(Domain Controller)安全加固保护.企业随着规模不断扩大,业务增多,信息安全建设是企业里一条只有重点没有终点...【详细内容】
2021-09-17  Vireshark    Tags:服务器安全   点击:(64)  评论:(0)  加入收藏
目录常见共享命令IPC$IPC$的利用条件1:开启了139、445端口2:目标主机开启了IPC$共享3:IPC连接报错IPC空连接空连接可以做什么?(毫无作用)IPC$非空连接IPC$非空连接可以做什么?di...【详细内容】
2021-09-16  网络说安全    Tags:系统安全   点击:(86)  评论:(0)  加入收藏
昨天一个老哥找到我,说他的服务器这几天一直被CC攻击,问我这边有没有什么解决的方法? 近年来,网络攻击事件越来越频繁,最常见的就是CC攻击和DDOS攻击,主要的区别就是针对的对象不...【详细内容】
2021-09-10  小蚁GDRAGON    Tags:cc攻击   点击:(58)  评论:(0)  加入收藏
网站页面上的登录操作,通常都是输入帐号密码,传输至网站后台验证。在网站页面、数据传输中,通过技术手段,都可以得到用户输入的信息,并可以修改,从而发起网络攻击。典型的如:使用自...【详细内容】
2021-08-30  修丹道的程序猿    Tags:登录方式   点击:(62)  评论:(0)  加入收藏
网络安全研究人员披露了一类影响主要 DNS 即服务 (DNSaaS) 提供商的新漏洞,这些漏洞可能允许攻击者从企业网络中窃取敏感信息。基础设施安全公司 Wiz 的研究人员 Shir Tamar...【详细内容】
2021-08-12  零日时代    Tags:漏洞   点击:(66)  评论:(0)  加入收藏
001暴力破解1. 指定用户名爆破密码传统型爆破思路,用户名可以通过猜测或者信息收集获得。猜测:admin、网站域名等信息收集:新闻发布人、whoami等2. 指定密码爆破用户名如果是后...【详细内容】
2021-07-23  KaliMa  今日头条  Tags:登陆框   点击:(85)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条