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

Incorrect handling over-large packets at dtls_ccm_decrypt_message() #98

Closed
jerrytesting opened this issue Aug 5, 2021 · 10 comments
Closed
Labels
please retest Please retest the related PR or commit, if that works for you

Comments

@jerrytesting
Copy link

Hello,

In both the master branch and develop branch, an illegal over-read bug has been found when the server handles a malicious message with the following values for the mentioned fields:

  1. Fragment length may be a larger number like 8143, whose value can be up to (2^24-1) bytes theoretically.
  2. the peer exists and is not null.

After the server handles this message in the normal way as follows(in the master branch), we enter into the function dtls_ccm_decrypt_message() at ccm.c:264.
1. 0x4e4b33 in dtls_ccm_decrypt_message /home/Research/benchmarks/tinydtls/ccm.c:264:5
2. 0x4dd76a in dtls_ccm_decrypt /home/Research/benchmarks/tinydtls/crypto.c:301:9
3. 0x4dd76a in dtls_decrypt /home/Research/benchmarks/tinydtls/crypto.c:561:9
4. 0x4cbfe7 in decrypt_verify /home/Research/benchmarks/tinydtls/dtls.c:3035:12
5. 0x4c9bbc in dtls_handle_message /home/Research/benchmarks/tinydtls/dtls.c:3746:25
6. 0x4c67bc in dtls_handle_read /home/Research/benchmarks/tinydtls/tests/dtls-server.c:177:10
7. 0x4c67bc in main /home/Research/benchmarks/tinydtls/tests/dtls-server.c:352:2
8. 0x7f8454dbb0b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/../csu/libc-start.c:308:16
9. 0x41c3bd in _start (/home/Research/benchmarks/tinydtls/tests/dtls-server+0x41c3bd)

In the function dtls_ccm_decrypt_message(), the value of variable lm is larger than the length of the current packet, whose value is less than 1400. Hence, an illegal memory access bug appears, which leads to the server crashing, memory leak and other effects.

From DTLS12 RFC, the server should have the ability to fragment large packets. If not, over-large packets should be refused.

In current both master and develop branches, this bug could be reproduced with this packet: ReproduciablePacket.

Could you kindly have a check? Thanks a lot.

@jerrytesting jerrytesting changed the title Incorrect handling over-large packets at decrypt_verify() Incorrect handling over-large packets at dtls_ccm_decrypt_message() Aug 5, 2021
@boaks
Copy link
Contributor

boaks commented Aug 7, 2021

static unsigned int
is_record(uint8 *msg, size_t msglen) {
  unsigned int rlen = 0;

  if (msglen >= DTLS_RH_LENGTH) { /* FIXME allow empty records? */
    uint16_t version = dtls_uint16_to_int(msg + 1);
    if ((((version == DTLS_VERSION) || (version == DTLS10_VERSION))
         && known_content_type(msg))) {
        rlen = DTLS_RH_LENGTH +
	dtls_uint16_to_int(DTLS_RECORD_HEADER(msg)->length);

      /* we do not accept wrong length field in record header */
      if (rlen > msglen)
	rlen = 0;
    }
  }

  return rlen;
}

For me that protects to use a record length, which exceeds the provided message length.

Unfortunately, I'm not able (allowed?) to clone your repo with the https://github.com/jerrytesting/tinydtls-illegalMemAccess.git . Therefore I can't reproduce nor see your setup.

@boaks
Copy link
Contributor

boaks commented Aug 7, 2021

Maybe the test/example dtls-server is the pain.

static int
dtls_handle_read(struct dtls_context_t *ctx) {
  int *fd;
  session_t session;
  static uint8 buf[DTLS_MAX_BUF];
  int len;

  fd = dtls_get_app_data(ctx);

  assert(fd);

  memset(&session, 0, sizeof(session_t));
  session.size = sizeof(session.addr);
  len = recvfrom(*fd, buf, sizeof(buf), MSG_TRUNC,
		 &session.addr.sa, &session.size);

  if (len < 0) {
    perror("recvfrom");
    return -1;
  } else {
    dtls_debug("got %d bytes from port %d\n", len, 
	     ntohs(session.addr.sin6.sin6_port));
    if (sizeof(buf) < (size_t)len) {
      dtls_warn("packet was truncated (%ld bytes lost)\n", len - sizeof(buf));
    }
  }

  return dtls_handle_message(ctx, &session, buf, len);
}    

Passing too large len values to dtls_handle_message will fail.

In my experience, using DTLS and truncated messages doesn't work at all.
For encrypted messages, if the MAC is cut of, decryption will not work.
For not encrypted handshake-messages, if parts are cut of, the hash in the FINISH will not match.
So, I would propose just to drop them ...

@jerrytesting
Copy link
Author

So sorry. I have made my repo public, and you can clone it with the same link to reproduce this bug.

Unfortunately, I'm not able (allowed?) to clone your repo with the https://github.com/jerrytesting/tinydtls-illegalMemAccess.git . Therefore I can't reproduce nor see your setup.

@jerrytesting
Copy link
Author

From my understanding, there are two problems,

(1) the test/example dtls-server is indeed one problem. When the length of packets is over sizeof(buf), servers still proceed to handle messages, which would lead to buffer over-read. This is the case for normal packets, whose real length is the same as the field value.

(2) For malformed packets, some filed values like Fragment Length are not the same as the real ones. So only checking the packet length when receiving them is not enough. I think servers should have a length check before reading every field (shown in the picture below). The packet that I provided is in this case.

22

@boaks
Copy link
Contributor

boaks commented Aug 8, 2021

(2) For malformed packets, some filed values like Fragment Length are not the same as the real ones. So only checking the packet length when receiving them is not enough. I think servers should have a length check before reading every field (shown in the picture below). The packet that I provided is in this case.

That's not the bug in the stacktrace, or?

AFAIK, handshake-message fragmentation is "under development" in a different branch.
In the develop branch, the checks are (dtls.c, handle_handshake):

  packet_length = dtls_uint24_to_int(hs_header->length);
  fragment_length = dtls_uint24_to_int(hs_header->fragment_length);
  fragment_offset = dtls_uint24_to_int(hs_header->fragment_offset);
  if (packet_length != fragment_length || fragment_offset != 0) {
    dtls_warn("No fragment support (yet)\n");
    return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE);
  }
  if (fragment_length + DTLS_HS_LENGTH != data_length) {
    dtls_warn("Fragment size does not match packet size\n");
    return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE);
  }

So at least in that branch, it's checked.

AFAIK, issue #54 and PR #62 are dealing with a similar topic.

@jerrytesting
Copy link
Author

I checked again just now, but this bug still exists in the development branch.

@jerrytesting
Copy link
Author

Here is the backtrace:
0 0x4ec24a in memxor (/home/Research/benchmarks/tcpdump/tinydtls/tests/dtls-server+0x4ec24a)
1 0x4ebb67 in encrypt (/home/Research/benchmarks/tcpdump/tinydtls/tests/dtls-server+0x4ebb67)
2 0x4ebe27 in dtls_ccm_decrypt_message (/home/Research/benchmarks/tcpdump/tinydtls/tests/dtls-server+0x4ebe27)
3 0x4ea6a7 in dtls_ccm_decrypt (/home/Research/benchmarks/tcpdump/tinydtls/tests/dtls-server+0x4ea6a7)
4 0x4ea53d in dtls_decrypt_params (/home/Research/benchmarks/tcpdump/tinydtls/tests/dtls-server+0x4ea53d)
5 0x4ea8df in dtls_decrypt (/home/Research/benchmarks/tcpdump/tinydtls/tests/dtls-server+0x4ea8df)
6 0x4cdd59 in decrypt_verify (/home/Research/benchmarks/tcpdump/tinydtls/tests/dtls-server+0x4cdd59)
7 0x4cba7c in dtls_handle_message (/home/Research/benchmarks/tcpdump/tinydtls/tests/dtls-server+0x4cba7c)
8 0x4c8043 in dtls_handle_read (/home/Research/benchmarks/tcpdump/tinydtls/tests/dtls-server+0x4c8043)
9 0x4c7510 in main (/home/Research/benchmarks/tcpdump/tinydtls/tests/dtls-server+0x4c7510)
10 0x7f3e0a9a70b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/../csu/libc-start.c:308:16
11 0x41c3bd in _start (/home/Research/benchmarks/tcpdump/tinydtls/tests/dtls-server+0x41c3bd)

@boaks
Copy link
Contributor

boaks commented Aug 8, 2021

The bug referring to dtls-server.c, dtls_handle_read? Yes, sure, the code snippet is from develop and so the bug isn't fixed there.

I don't know, what the developer would like to go for. I could assume, to adapt the server according the client implementation. Or keep it to get the "warning", but then drop the messages, or just reduce the len.

@obgm
If you can spend some time into this, that would be great.

@boaks
Copy link
Contributor

boaks commented Jan 25, 2023

Fixed with PR #184

@boaks boaks added the please retest Please retest the related PR or commit, if that works for you label Jan 25, 2023
@boaks
Copy link
Contributor

boaks commented Feb 28, 2023

Thanks for retesting and closing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
please retest Please retest the related PR or commit, if that works for you
Projects
None yet
Development

No branches or pull requests

2 participants