Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Case Analysis of Netty Service being attacked

2025-04-01 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >

Share

Shulou(Shulou.com)05/31 Report--

This article introduces the relevant knowledge of "Netty service attack case analysis". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

Prelude to the story

Netty service is a relatively marginal service of the company, only one device is in use, and the code is written by the previous technology Leader, and there is always a rush schedule, so there is no time to solve this problem thoroughly.

When I was attacked, I didn't check the code. When I saw the crazy request, the CPU was full, and the log was full, I thought I was attacked by DDoS.

Several temporary measures have been taken:

Detach the server to ensure that when the service is attacked, it does not drag down other services

Changed an IP and port

Add a blacklist to the IP of the attack

In the code layer, an illegal request was found to force the connection to be closed

Add log information to trace the attack message and source

Report the IP (Shanghai Aliyun) that attacked the service.

But it wasn't long before the hackers came to the door again, attacking once every ten and a half days, as if they knew the service IP and the background code.

This is not, today was caught, and before the addition of log printing, but also got the content of the attack message, reproduced the attack operation.

/ / message 8000002872FE1D130000000000000002000186A00001977C0000000000000000000000000000000000000000 of the attacker's first attempt / / message 8000002872FE1D130000000000000002000186A00001977C00000000000000000000000000000000 of the attacker's second attempt

In the above message, the first message triggered the attack, and the second message had no effect (the format of the normal service message is the same).

The following will take you to analyze the logic of the attack and the vulnerabilities in the code.

Knowledge reserve

To understand the principle of attack, we need to have some technical knowledge of Netty. The code on how Netty implements client-side and server-side will not be expanded here. You can take a look at the implementation example: https://github.com/secbr/netty-all/tree/main/netty-decoder

Let's focus on custom decoders and io.netty.buffer.ByteBuf. The custom decoder is used to parse the message, and the message content is cached and transmitted through ByteBuf.

The format of the attack message above indicates that the hacker has "guessed" that we are transmitting content based on the hexadecimal Btye format (the hacker even knows it).

Custom decoder

To customize the decoder, inherit the MessageToMessageDecoder class and implement the decode method. Here's the sample code:

Public class MyDecoder extends MessageToMessageDecoder {@ Override protected void decode (ChannelHandlerContext ctx, ByteBuf in, List out) {}}

The logic of parsing the message is processed in the decode method. ByteBuf in is the container that receives incoming messages, and List out is used to output the results after parsing.

Let's take a look at the code with bug (desensitized):

Protected void decode (ChannelHandlerContext ctx, ByteBuf in, List 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 ();}}

The above code is fine when running normal business, but when attacked, it goes into a dead loop. Therefore, although the operation of closing the connection is added to the business process, it is also invalid.

Before analyzing the above code, we have to analyze the principle of ByteBuf in detail.

The principle of ByteBuf

Two indexes are maintained in ByteBuf: one index (readIndex) for reading and one index (writeIndex) for writing.

When reading from ByteBuf, readIndex is incremented by the number of bytes that have been read, and when data is written to ByteBuf, writeIndex is also incremented.

Netty-ByteBuf

The above figure shows the attack message as an example, and the attacker uses 44 bytes of message to attack. Because hexadecimal is used, two characters take up 1 byte.

The starting position of both readIndex and writeIndex has an index position of 0, and the corresponding index is advanced when the readXXX or writeXXX method in ByteBuf is executed. Not when the operation of the setXXX or getXXX method is performed.

After understanding the basic processing principle of ByteBuf, we will compare the attacker's message and source code to restore the attack process.

Attack restore

The following is directly through the step-by-step analysis of the source code, mainly involving the methods of the ByteBuf class. The message of a valid attack is the first message mentioned above.

/ / message 8000002872FE1D130000000000000002000186A00001977C0000000000000000000000000000000000000000 attempted by the attacker for the first time

Let's look at the code:

Int readableBytes = in.readableBytes ()

This line of code gets the number of bytes that can be read in the current ByteBuf through the readableBytes method. The above attack message has 88 characters, so here you get 44 bytes.

When the readableBytes is greater than 3, the specific parsing processing is performed:

In.skipBytes (2)

Obviously, two bytes were skipped through the skipBytes method.

Netty-ByteBuf

Int pkgLength = in.readUnsignedShort ()

Through the readUnsignedShort method, the content of 2 bytes is obtained. The hexadecimal value of the two bytes is "0028" and the corresponding decimal value is "40". The meaning of these two bytes in the message is the length of (part or the whole) of the message.

There are often two algorithms for the length of a message: first, the length represents the length of the entire message (the meaning used in the service); second, the length represents the length of the message after the first 4 bytes (the meaning used by the attacker).

In fact, it is precisely because of the definition of the length meaning that the normal business can be executed and the attack message will enter an endless loop.

Let's continue to share the code:

In.readerIndex (in.readerIndex ()-4)

With the calls of skipBytes and readUnsignedShort above, the read index of ByteBuf has run to the fourth byte. So here in.readerIndex () returns a value of 4, and the purpose of in.readerIndex (4-4) is to reset the read index to 0, that is, to read from scratch.

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

This judgment is made after the read index is moved to 0 to see if the number of readable bytes of the message is less than the number of bytes specified in the message content. Obviously, the corresponding value of in.readableBytes () is 44 bytes, while pkgLength is 40 bytes, so there is no return.

Out.add (in.readBytes (pkgLength))

Read 40 bytes for output. There are four bytes left, and the readIndex points to the location of the 40th byte.

ReadableBytes = in.readableBytes ()

Since readIndex has already pointed to the 40th byte, the number of readable bytes at this time is 4.

Then, enter the second cycle. At this point, a magical situation arises. We can see that the message values of the last 4 bytes of the attack are all 0.

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

So after skipping 2 bytes, readIndex gets the values of 43 and 44 bytes for 42 and 44 bytes: 0.

In.readerIndex (in.readerIndex ()-4)

The above code sets the readIndex to the 40th byte.

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

At this point, you will find that the return value of readableBytes is 4, but pkgLength has become 0 and will not return.

Then something happens when you read the content:

Out.add (in.readBytes (pkgLength)); / / there are four bytes left here, readableBytes = in.readableBytes ()

The number of bytes read by the above readBytes is 0, while readableBytes is always 4. At this point, the whole while cycle enters an endless loop, consuming a lot of CPU resources.

At this time, it is not over. At most, the CPU is only run to 100%, but when the empty characters are constantly written to the buffer area where the data is received, the buffer begins to frantically call the Handler that handles the business, further intruding into the business processing logic.

Although the business logic layer makes a judgment and closes the connection, it has nothing to do with the connection at this time. The while loop has entered an endless loop, and it is useless to close the connection. At the same time, the business layer has log output, and a large number of logs are output to the disk, resulting in the disk being full.

It finally leads to CPU monitoring and disk monitoring alarm of the server. At first glance, I thought it was another DDoS attack.

This is the end of the content of "Netty Service attack case Analysis". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Servers

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report