大家好,今天来为大家解答Netty服务器安全攻防战:成功击退恶意攻击,守护稳定运行这个问题的一些问题点,包括也一样很多人还不知道,因此呢,今天就来为大家分析分析,现在让我们一起来看看吧!如果解决了您的问题,还望您关注下本站哦,谢谢~
前言春节快到了,我以为完成手头的任务就可以准备过年了。没想到,Netty服务器再次遭到攻击。当我们收到服务器警报(CPU激增警报)消息时,我们知道对方再次发起攻击。
之前就留给下面的兄弟来解决了。这次,为了过一个好的新年,我决定亲自动手,把事情摆平。
故事前奏Netty服务是公司比较边缘的服务。只有一台设备在使用,代码是前任技术负责人(已辞职)编写的。另外,我们总是按计划进行,所以没有花时间彻底解决问题。
当我被攻击时,我没有检查代码。我看到疯狂的请求、满载的CPU和满载的日志,所以我认为这是一次DDoS攻击。
采取了多项临时措施:
将服务器分开,保证该服务在受到攻击时不会导致其他服务瘫痪;更改IP 和端口;添加攻击IP黑名单;在代码层,如果发现非法请求,则强制关闭连接;添加日志信息,追溯攻击报告文和来源;报告攻击该服务的IP(上海阿里云);但没过多久,黑客又找上门来,每隔十天半天就会攻击一次,仿佛知道了服务IP和后台代码,挥之不去。
这不,我今天被抓了,之前还加了日志打印,还获取了攻击报文内容,重现了攻击操作。
//攻击者第一次尝试消息8000002872FE1D130000000000000002000186A00001977C000000000000000000000000000000000000000000 //攻击者第二次尝试消息8000002872FE1D1300 00000000000002000186A00001977C0000000000000000000000000000000 对于上述消息,第一条消息触发了攻击,但第二条消息没有影响(和正常业务的消息格式相同)。
接下来我就带大家分析一下攻击的逻辑以及代码中的漏洞。
知识储备要了解攻击原理,我们需要对Netty有一定的技术知识。这里我不会详细介绍Netty 如何实现客户端和服务器代码。你可以看一下实现示例:https://github.com/secbr/netty-all/tree/main/netty-decoder
让我们关注自定义解码器和io.netty.buffer.ByteBuf。使用自定义解码器解析消息,消息内容通过ByteBuf进行缓存和传输。
上述攻击报文格式表明,黑客已经“猜测”到我们基于十六进制Btye格式传输内容(黑客其实也知道这一点)。
自定义解码器要自定义解码器,只需继承MessageToMessageDecoder类并实现decode方法即可。示例代码如下所示:
publicclassMyDecoderextendsMessageToMessageDecoderByteBuf{@Overrideprotectedvoiddecode(ChannelHandlerContextctx,ByteBufin,ListObjectout){}}解析消息的逻辑是在decode方法中处理的。其中,ByteBuf in 是接收传入消息的容器,List out 用于输出解析后的结果。
我们看一下有bug的代码(已脱敏):
protectedvoiddecode(ChannelHandlerContextctx,ByteBufin,ListObjectout){intreadableBytes=in.readerIndex();while(readableBytes3){in.skipBytes(2);intpkgLength=in.readUnsignedShort();in.readerIndex(in.readerIndex()-4); if(in.readBytes()pkgLength){return;}out.add(in.readBytes(pkgLength));readBytes=in.readBytes();}} 上面的代码在正常业务运行时是没有问题的,但是当受到攻击时,进入无限循环。因此,虽然在业务处理时添加了关闭连接的操作,但是是无效的。
在分析上面的代码之前,我们首先要详细分析一下ByteBuf的原理。
ByteBuf的原理ByteBuf会维护两个索引:一个用于读的索引(readIndex),一个用于写的索引(writeIndex)。
当从ByteBuf 读取时,readIndex 将增加已读取的字节数。当向ByteBuf写入数据时,writeIndex也会递增。
netty-ByteBuf
上图以攻击报文为例。攻击者使用44字节的数据包进行攻击。由于使用16进制,两个字符占用1个字节。
readIndex和writeIndex的起始位置的索引位置都是0。当执行ByteBuf中的readXXX或writeXXX方法时,相应的索引会前进。执行setXXX 或getXXX 方法操作时不会。
了解了ByteBuf的基本处理原理后,我们将通过对比攻击者的消息和源代码来还原攻击过程。
攻击还原下面直接通过源码一步步分析,主要涉及ByteBuf类的方法。有效的攻击消息就是上面提到的第一条消息。
//攻击者的第一次尝试是消息8000002872FE1D130000000000000002000186A00001977C00000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000001
intreadBytes=in.readBytes();这行代码使用ReadableBytes 方法获取当前ByteBuf 中可以读取的字节数。上面的攻击消息有88个字符,所以这里得到了44个字节。
当ReadBytes 大于3 时,进行具体解析处理:
in.skipBytes(2);显然,通过skipBytes方法跳过了两个字节。
netty-ByteBuf
intpkgLength=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.readBytes()pkgLength){return;}这个判断是看读索引移动到0后,消息的可读字节数是否小于消息内容中指定的字节数。显然, in.readBytes()对应的值为44字节,pkgLength为40字节,不会返回。
out.add(in.readBytes(pkgLength));读取40字节并输出。还剩下4个字节的内容,readIndex指向第40个字节。
readBytes=in.readBytes();由于readIndex已经指向第40个字节,因此此时可读字节数为4。
然后,进入第二个循环。这时,神奇的情况发生了。我们可以看到攻击报文的最后4个字节全部为0。
in.skipBytes(2);intpkgLength=in.readUnsignedShort();因此,跳过2个字节后,readIndex为42,pkgLength得到第43和44个字节的值:0。
in.readerIndex(in.readerIndex()-4);上面的代码将readIndex设置为第40个字节。
if(in.readBytes()pkgLength){return;}这时候你会发现可读Bytes的返回值为4,但是pkgLength却变成了0,不会返回。
阅读内容时出现一种情况:
out.add(in.readBytes(pkgLength));//这里还剩下4个字节readBytes=in.readBytes();上面readBytes读取的字节数为0,而readBytes始终为4。此时整个while循环进入死循环,消耗大量CPU资源。
事情还没有结束。最多CPU运行到100%。然而,当不断向接收数据的缓冲区写入空字符时,缓冲区开始疯狂调用处理业务的Handler,进一步侵入业务处理逻辑。
虽然业务逻辑层已经做出了判断并关闭了连接,但是此时与连接无关。 while循环已经进入无限循环,关闭连接没有任何效果。同时业务层有日志输出,大量日志输出到磁盘,导致磁盘被占满。
最终出现服务器CPU监控和磁盘监控报警。乍一看,我还以为又是一次DDoS攻击……
小结综上所述,实际上是攻击者传输的报文长度与报文中指定的长度不一致,导致解析报文时出现死循环。
一旦发现问题,解决起来就很容易了。其实我也从这件事中得到了一些启发。首先,当你遇到问题时,正视它并解决它往往是最好的解决办法。逃避只能推迟问题的发生,却不能解决问题。第二,只要静下心来一步步分析,很少有解决不了的问题。
END,本文到此结束,如果可以帮助到大家,还望关注本站哦!
本文采摘于网络,不代表本站立场,转载联系作者并注明出处:https://www.iotsj.com//kuaixun/7440.html
用户评论
真是太刺激了,没想到还能抓住凶手!
有11位网友表示赞同!
我一直在担心这个问题呢,看来问题解决了太好了!
有18位网友表示赞同!
N次攻击可真让人吓人啊,还好最终抓到人了。
有13位网友表示赞同!
心疼一下那个Netty服务器,受了这么多委屈啊。
有6位网友表示赞同!
这个新闻太值钱了!终于解开了大家心中的谜团?
有18位网友表示赞同!
这么多次攻击,背后肯定有不可告人的秘密吧。
有17位网友表示赞同!
希望这些犯罪分子得到应有的惩罚!
有10位网友表示赞同!
以后使用Netty服务器更加安心了!
有14位网友表示赞同!
这个消息来得及时啊,让我放心很多!
有19位网友表示赞同!
终于知道是谁在捣乱了!太意外了。
有5位网友表示赞同!
现在可以好好研究一下攻击手段,预防下一次了?
有11位网友表示赞同!
好想了解一下攻击的详细过程!
有11位网友表示赞同!
Netty服务器真的很好用啊,值得我们保护!
有15位网友表示赞同!
这样一来,那些想要攻击我们的罪犯应该会害怕了吧。
有19位网友表示赞同!
以后再看到Netty服务器就想到这次事件!
有10位网友表示赞同!
真是令人兴奋的消息啊,终于可以安心使用Netty服务了!
有5位网友表示赞同!
恭喜抓到这些坏人,为世界安全贡献力量!
有8位网友表示赞同!
这个新闻真棒,让人感觉社会治安越来越好了!
有9位网友表示赞同!
希望大家能更加关注网络安全问题!
有18位网友表示赞同!
Netty服务器太厉害了,经历这么多攻击还能运转正常呢!
有12位网友表示赞同!