Project: libcoap (obgm/libcoap), language: c++
Vulnerability instance: libcoap.cve-2023-35862
Sanitizer: address

================= Bug Report (1/1) ==================
## Source: GitHub Issue
## URL: https://github.com/obgm/libcoap/issues/1117
## Description:
Issue: obgm/libcoap#1117
Title: Global-buffer-overflow in `coap_parse_oscore_conf_mem` function in `src/coap_oscore.c`
State: closed
Created by: grandnew
Created at: 2023-05-21 14:10:09+00:00

Issue Body:
## Environment

- libcoap version:    v4.3.1-162-g6f79db0
- Build System:             Make
- Operating System:         Linux
- Operating System Version: Debian GNU/Linux 11 (bullseye)
- Hosted Environment:       None

## Problem Description

There is a global-buffer-overflow bug in the `coap_parse_oscore_conf_mem` function in `src/coap_oscore.c`.

### Expected Behavior

No crash.

### Actual Behavior

Crash when enhanced with ASan.

### Steps to reproduce

1. Build `libcoap` with ASan
```sh
CC=clang CFLAGS="-g -fsanitize=address" ./autogen.sh
CC=clang CFLAGS="-g -fsanitize=address" ./configure --disable-doxygen --disable-manpages --enable-tests --disable-documentation --enable-examples --enable-shared
CC=clang CFLAGS="-g -fsanitize=address" make -j
```
2. Compile `overflow.c` (as shown follows)
```
clang overflow.c -I/root/libcoap/include -I/root/libcoap /root/libcoap/.libs/libcoap-3-gnutls.a  /usr/local/lib/libgnutls.so -g -fsanitize=address -o overflow
```

3. Run `overflow` and detect ASan error
```
==869262==ERROR: AddressSanitizer: global-buffer-overflow on address 0x5567c1231cea at pc 0x5567c1079006 bp 0x7ffcdaa591c0 sp 0x7ffcdaa58970
READ of size 12 at 0x5567c1231cea thread T0
    #0 0x5567c1079005 in MemcmpInterceptorCommon(void*, int (*)(void const*, void const*, unsigned long), void const*, void const*, unsigned long) (/root/libcoap/overflow+0x57005) (BuildId: 54eb8810f12f7eb05271c5e5354411ec106ffe25)
    #1 0x5567c10794f9 in memcmp (/root/libcoap/overflow+0x574f9) (BuildId: 54eb8810f12f7eb05271c5e5354411ec106ffe25)
    #2 0x5567c1128e03 in coap_parse_oscore_conf_mem /root/libcoap/src/coap_oscore.c:1849:11
    #3 0x5567c112849d in coap_new_oscore_conf /root/libcoap/src/coap_oscore.c:2020:37
    #4 0x5567c111ca1f in main /root/libcoap/overflow.c:24:17
    #5 0x7fb67e995d09 in __libc_start_main csu/../csu/libc-start.c:308:16
    #6 0x5567c105da29 in _start (/root/libcoap/overflow+0x3ba29) (BuildId: 54eb8810f12f7eb05271c5e5354411ec106ffe25)

0x5567c1231cea is located 54 bytes to the left of global variable '.str.74' defined in '/root/libcoap/src/coap_oscore.c:1790' (0x5567c1231d20) of size 14
  '.str.74' is ascii string 'replay_window'
0x5567c1231cea is located 22 bytes to the left of global variable '.str.73' defined in '/root/libcoap/src/coap_oscore.c:1788' (0x5567c1231d00) of size 11
  '.str.73' is ascii string 'id_context'
0x5567c1231cea is located 0 bytes to the right of global variable '.str.72' defined in '/root/libcoap/src/coap_oscore.c:1787' (0x5567c1231ce0) of size 10
  '.str.72' is ascii string 'sender_id'
SUMMARY: AddressSanitizer: global-buffer-overflow (/root/libcoap/overflow+0x57005) (BuildId: 54eb8810f12f7eb05271c5e5354411ec106ffe25) in MemcmpInterceptorCommon(void*, int (*)(void const*, void const*, unsigned long), void const*, void const*, unsigned long)
Shadow bytes around the buggy address:
  0x0aad7823e340: 00 f9 f9 f9 f9 f9 f9 f9 00 00 00 00 04 f9 f9 f9
  0x0aad7823e350: f9 f9 f9 f9 00 00 00 00 00 00 03 f9 f9 f9 f9 f9
  0x0aad7823e360: 05 f9 f9 f9 06 f9 f9 f9 00 00 00 00 00 00 06 f9
  0x0aad7823e370: f9 f9 f9 f9 06 f9 f9 f9 04 f9 f9 f9 00 f9 f9 f9
  0x0aad7823e380: 05 f9 f9 f9 05 f9 f9 f9 00 04 f9 f9 00 00 07 f9
=>0x0aad7823e390: f9 f9 f9 f9 00 06 f9 f9 00 04 f9 f9 00[02]f9 f9
  0x0aad7823e3a0: 00 03 f9 f9 00 06 f9 f9 00 01 f9 f9 00 01 f9 f9
  0x0aad7823e3b0: 00 01 f9 f9 00 06 f9 f9 00 04 f9 f9 00 00 01 f9
  0x0aad7823e3c0: f9 f9 f9 f9 00 00 04 f9 f9 f9 f9 f9 00 00 02 f9
  0x0aad7823e3d0: f9 f9 f9 f9 00 00 02 f9 f9 f9 f9 f9 00 00 04 f9
  0x0aad7823e3e0: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==869262==ABORTING
```


### Code to reproduce this issue

```cpp
// overflow.c
#include "coap3/coap_internal.h"
#include "oscore/oscore.h"
#include "oscore/oscore_context.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
 static const char conf_data[] =
    "master_secret,hex,\"0102030405060708090a0b0c0d0e0f10\"\n"
    "master_salt,hex,\"9e7ca92223786340\"\n"
    "sender_id,hex,\"\"\n"
    "recipient_id,hex,\"01\"\n";
  const coap_str_const_t conf = { sizeof(conf_data)-1,
                                  (const uint8_t *)conf_data };
  coap_context_t ctx[1];
  coap_oscore_conf_t *oscore_conf;
  cose_encrypt0_t cose[1];
  uint8_t nonce_buffer[13];
  coap_bin_const_t nonce = { 13, nonce_buffer };

  memset(&ctx, 0, sizeof(ctx));
  oscore_conf = coap_new_oscore_conf(conf, NULL, NULL, 0);

  oscore_free_contexts(ctx);
  return 0;
}
```

## Debug Logs

```
(gdb) b coap_oscore.c:1849
Breakpoint 1 at 0x106d39: file src/coap_oscore.c, line 1849.
(gdb) r
Starting program: /root/libcoap/overflow 
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, coap_parse_oscore_conf_mem (conf_mem=...) at src/coap_oscore.c:1849
1849          if (memcmp(oscore_config[i].keyword, keyword.s, keyword.length) == 0 &&
(gdb) display oscore_config[i]
1: oscore_config[i] = {keyword = 0x562f6227aca0 <str> "master_secret", encoding = 3, offset = 0, text_mapping = 0x0}
(gdb) display keyword
2: keyword = {length = 13, 
  s = 0x562f62279660 <main.conf_data> "master_secret,hex,\"0102030405060708090a0b0c0d0e0f10\"\nmaster_salt,hex,\"9e7ca92223786340\"\nsender_id,hex,\"\"\nrecipient_id,hex,\"01\"\n"}
(gdb) c
Continuing.

Breakpoint 1, coap_parse_oscore_conf_mem (conf_mem=...) at src/coap_oscore.c:1849
1849          if (memcmp(oscore_config[i].keyword, keyword.s, keyword.length) == 0 &&
1: oscore_config[i] = {keyword = 0x562f6227aca0 <str> "master_secret", encoding = 3, offset = 0, text_mapping = 0x0}
2: keyword = {length = 11, s = 0x562f62279695 <main.conf_data+53> "master_salt,hex,\"9e7ca92223786340\"\nsender_id,hex,\"\"\nrecipient_id,hex,\"01\"\n"}
(gdb) c
Continuing.

Breakpoint 1, coap_parse_oscore_conf_mem (conf_mem=...) at src/coap_oscore.c:1849
1849          if (memcmp(oscore_config[i].keyword, keyword.s, keyword.length) == 0 &&
1: oscore_config[i] = {keyword = 0x562f6227acc0 <str> "master_salt", encoding = 3, offset = 8, text_mapping = 0x0}
2: keyword = {length = 11, s = 0x562f62279695 <main.conf_data+53> "master_salt,hex,\"9e7ca92223786340\"\nsender_id,hex,\"\"\nrecipient_id,hex,\"01\"\n"}
(gdb) c
Continuing.

Breakpoint 1, coap_parse_oscore_conf_mem (conf_mem=...) at src/coap_oscore.c:1849
1849          if (memcmp(oscore_config[i].keyword, keyword.s, keyword.length) == 0 &&
1: oscore_config[i] = {keyword = 0x562f6227aca0 <str> "master_secret", encoding = 3, offset = 0, text_mapping = 0x0}
2: keyword = {length = 9, s = 0x562f622796b8 <main.conf_data+88> "sender_id,hex,\"\"\nrecipient_id,hex,\"01\"\n"}
(gdb) c
Continuing.

Breakpoint 1, coap_parse_oscore_conf_mem (conf_mem=...) at src/coap_oscore.c:1849
1849          if (memcmp(oscore_config[i].keyword, keyword.s, keyword.length) == 0 &&
1: oscore_config[i] = {keyword = 0x562f6227acc0 <str> "master_salt", encoding = 3, offset = 8, text_mapping = 0x0}
2: keyword = {length = 9, s = 0x562f622796b8 <main.conf_data+88> "sender_id,hex,\"\"\nrecipient_id,hex,\"01\"\n"}
(gdb) c
Continuing.

Breakpoint 1, coap_parse_oscore_conf_mem (conf_mem=...) at src/coap_oscore.c:1849
1849          if (memcmp(oscore_config[i].keyword, keyword.s, keyword.length) == 0 &&
1: oscore_config[i] = {keyword = 0x562f6227ace0 <str> "sender_id", encoding = 3, offset = 16, text_mapping = 0x0}
2: keyword = {length = 9, s = 0x562f622796b8 <main.conf_data+88> "sender_id,hex,\"\"\nrecipient_id,hex,\"01\"\n"}
(gdb) c
Continuing.

Breakpoint 1, coap_parse_oscore_conf_mem (conf_mem=...) at src/coap_oscore.c:1849
1849          if (memcmp(oscore_config[i].keyword, keyword.s, keyword.length) == 0 &&
1: oscore_config[i] = {keyword = 0x562f6227aca0 <str> "master_secret", encoding = 3, offset = 0, text_mapping = 0x0}
2: keyword = {length = 12, s = 0x562f622796c9 <main.conf_data+105> "recipient_id,hex,\"01\"\n"}
(gdb) c
Continuing.

Breakpoint 1, coap_parse_oscore_conf_mem (conf_mem=...) at src/coap_oscore.c:1849
1849          if (memcmp(oscore_config[i].keyword, keyword.s, keyword.length) == 0 &&
1: oscore_config[i] = {keyword = 0x562f6227acc0 <str> "master_salt", encoding = 3, offset = 8, text_mapping = 0x0}
2: keyword = {length = 12, s = 0x562f622796c9 <main.conf_data+105> "recipient_id,hex,\"01\"\n"}
(gdb) c
Continuing.

Breakpoint 1, coap_parse_oscore_conf_mem (conf_mem=...) at src/coap_oscore.c:1849
1849          if (memcmp(oscore_config[i].keyword, keyword.s, keyword.length) == 0 &&
1: oscore_config[i] = {keyword = 0x562f6227ace0 <str> "sender_id", encoding = 3, offset = 16, text_mapping = 0x0}
2: keyword = {length = 12, s = 0x562f622796c9 <main.conf_data+105> "recipient_id,hex,\"01\"\n"}
(gdb) c
Continuing.

[Then crashes]
```




Comments:
Comment by mrdeep1 on 2023-05-22 08:44:43+00:00:
It is appreciated that you are checking the libcoap code for potential issues and giving detail to be able to reproduce the issue.  This has been fixed in #1118 which is ready for further testing.

Note that you need to add `coap_context_oscore_server(ctx, oscore_conf);` before `oscore_free_contexts(ctx);` to your overflow.c file to prevent memory leak errors being reported.

---

Comment by risicle on 2023-08-19 11:33:47+00:00:
CVE-2023-35862 claims this makes 4.3.1 vulnerable, but I think I'm right in saying oscore code wasn't even present in 4.3.1?

---

Comment by mrdeep1 on 2023-08-19 12:41:49+00:00:
@risicle You are correct.  The OSCORE code was added in sometime after 4.3.1 was released, and this issue is fixed in #1118 which is included in 4.3.2rc1 and later..

Commit References:
54eb8810f12f7eb05271c5e5354411ec106ffe25

Build script:
#!/bin/bash -eu
# Minimized build script with only core build commands
set -eu
./autogen.sh && ./configure --disable-doxygen --disable-manpages \
                            --disable-dtls                       \
    && make -j$(nproc)
make -C tests/oss-fuzz -f Makefile.oss-fuzz -j$(nproc)

Dockerfile:
FROM hwiwonlee/secb.base:latest
RUN apt-get update && apt-get install -y make autoconf automake libtool pkg-config
RUN git clone https://github.com/obgm/libcoap libcoap
RUN git -C libcoap checkout c694baead2f9b408a7598e0b85c2f257ea8c9651
WORKDIR $SRC/libcoap
COPY build.sh $SRC/

Additional files: