Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Denial of Service #1013

Closed
artfire52 opened this issue Aug 29, 2022 · 5 comments
Closed

Denial of Service #1013

artfire52 opened this issue Aug 29, 2022 · 5 comments

Comments

@artfire52
Copy link

artfire52 commented Aug 29, 2022

The bug
It is possible to create a denial of service by sending a malformed packet. The server will be trap in an infinite loop and consume lot of memory. I create an issue instead of sending mail following instruction from How to report a security issue? #902

Reproduce

To reproduce the denial of service, you have to send a packet with a null size.

Explanation

The function data_received in file binary_server_asyncio.py (opcua-asyncio/asyncua/server/binary_server_asyncio.py) continue to work on the same buffer.

def data_received(self, data):
        self._buffer += data
        # try to parse the incoming data
        while self._buffer:
            try:
                buf = Buffer(self._buffer)
                try:
                    header = header_from_binary(buf)
                except NotEnoughData:
                    logger.debug('Not enough data while parsing header from client, waiting for more')
                    return
                if len(buf) < header.body_size:
                    logger.debug('We did not receive enough data from client. Need %s got %s', header.body_size,
                                 len(buf))
                    return
                # we have a complete message
                self.messages.put_nowait((header, buf))
                self._buffer = self._buffer[(header.header_size + header.body_size):]
            except Exception:
                logger.exception('Exception raised while parsing message from client')
                return

The value of (header.header_size + header.body_size) is equal to zero. In the function header_from_binary in (opcua-asyncio/asyncua/ua/ua_binary.py), the bod_size is equal to zero at the beginning (due to our malformed packet). At the end hdr.header_size is equal to 12 and hdr.body_size is equal to -12.

def header_from_binary(data):
    hdr = ua.Header()
    hdr.MessageType, hdr.ChunkType, hdr.packet_size = struct.unpack("<3scI", data.read(8))
    hdr.body_size = hdr.packet_size - 8
    if hdr.MessageType in (ua.MessageType.SecureOpen, ua.MessageType.SecureClose, ua.MessageType.SecureMessage):
        hdr.body_size -= 4
        hdr.ChannelId = Primitives.UInt32.unpack(data)
        hdr.header_size = 12
    return hdr

So in the function data_received, the buffer is never updated, then we are trapped in an infinite loop.

Version

Python-Version:Python 3.8.10

opcua-asyncio Version (e.g. master branch, 0.9):
branch master, commit 54e54fa (last commit 29/08/2022)

@GoetzGoerisch
Copy link

Thank you @artfire52

For reference this is CVE-2022-25304 and GHSA-mfpj-3qhm-976m

GitHub already raised an alert in our sample server implementation.

@artfire52
Copy link
Author

Actually for this denial of service only one message is required, it is not exploiting sending several chunks without the final one. For the example, one opensecure channel request with a null size in the field size of OPC UA Connection Protocol Message header is sufficient to perform a denial of service. Sending a hello message is not required for instance.

@kohtala

This comment was marked as outdated.

@kohtala
Copy link
Contributor

kohtala commented Sep 19, 2022

@GoetzGoerisch , @schroeder- commented on #1023 that this vulnerability is not CVE-2022-25304. Hence the #1039 does not fix that vulnerability.

@schroeder-
Copy link
Contributor

Closed via #1039

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants