Lucene search

K
hackeroneDubekH1:2629968
HistoryJul 30, 2024 - 5:16 a.m.

curl: CVE-2024-7264: ASN.1 date parser overread

2024-07-3005:16:36
dubek
hackerone.com
27
cve-2024-7264
stack read overflow
heap read overflow
gtime2str function
curl_dyn_addf function
asn.1 date parser
addresssanitizer error

CVSS3

6.5

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

REQUIRED

Scope

UNCHANGED

Confidentiality Impact

NONE

Integrity Impact

NONE

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H

AI Score

7.2

Confidence

High

EPSS

0.001

Percentile

23.6%

Summary:

When a specially-crafted certificate is passed to Curl_extract_certinfo to parse, it may read bytes beyond the end of the buffer in which the certificate is held. According to the application, this may be a stack read overflow or a heap read overflow.

Specifically the issue is in function GTime2str, in which the specially-crafted input may cause it to set fracl = -1 and then pass it to Curl_dyn_addf, which in turn treats this -1 as “no length given” and goes on to run strlen(tzp) which goes beyond the end of the certificate buffer (assuming there are no null bytes).

I believe the issue is in this loop (in lib/vtls/x509asn1.c):

 524     /* Strip leading zeroes in fractional seconds. */
 525     for(fracl = tzp - fracp - 1; fracl && fracp[fracl - 1] == '0'; fracl--)
 526       ;

If tzp == fracp, then fracl is set to -1 in the loop initialization.

I tested this on curl 8.9.0 commit 2a59c8d4cebfd199f930213ee82ae95f71e44578 (2024-07-24). I haven’t looked when the issue was introduced.

Steps To Reproduce:

  1. Compile libcurl with -fsanitize=address and with gnutls. I used clang. CC=clang CFLAGS=-fsanitize=address ../configure --disable-shared --enable-debug --with-gnutls=/usr/lib/aarch64-linux-gnu
  2. Compile the attached poc.c program which uses libcurl’s Curl_extract_certinfo.
  3. Run ./poc bad_cert_1.bin

The resulting report from AddressSanitizer:

=================================================================
==2166==ERROR: AddressSanitizer: stack-buffer-overflow on address 0xffffaae02020 at pc 0xaaaad3fedb44 bp 0xffffee270350 sp 0xffffee26fb40
READ of size 4471 at 0xffffaae02020 thread T0
    #0 0xaaaad3fedb40 in strlen (/root/work/curl/fuzz2/tests/unit/poc+0x11db40) (BuildId: 950d22dbc354c1f19b0a0459aa9b72f968a5aff4)
    #1 0xaaaad40dfb58 in formatf /root/work/curl/fuzz2/lib/../../lib/mprintf.c:883:15
    #2 0xaaaad40e1f14 in Curl_dyn_vprintf /root/work/curl/fuzz2/lib/../../lib/mprintf.c:1105:9
    #3 0xaaaad427c2ec in Curl_dyn_vaddf /root/work/curl/fuzz2/lib/../../lib/dynbuf.c:198:8
    #4 0xaaaad427c844 in Curl_dyn_addf /root/work/curl/fuzz2/lib/../../lib/dynbuf.c:231:12
    #5 0xaaaad41f0338 in GTime2str /root/work/curl/fuzz2/lib/../../lib/vtls/x509asn1.c:542:10
    #6 0xaaaad41ec5fc in ASN1tostr /root/work/curl/fuzz2/lib/../../lib/vtls/x509asn1.c:632:14
    #7 0xaaaad41eb410 in Curl_extract_certinfo /root/work/curl/fuzz2/lib/../../lib/vtls/x509asn1.c:1185:12
    #8 0xaaaad40b4f4c in main /root/work/curl/fuzz2/tests/unit/poc.c:36:14
    #9 0xffffac9b84c0 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #10 0xffffac9b8594 in __libc_start_main csu/../csu/libc-start.c:360:3
    #11 0xaaaad3fd886c in _start (/root/work/curl/fuzz2/tests/unit/poc+0x10886c) (BuildId: 950d22dbc354c1f19b0a0459aa9b72f968a5aff4)

Address 0xffffaae02020 is located in stack of thread T0 at offset 8224 in frame
    #0 0xaaaad40b4cc8 in main /root/work/curl/fuzz2/tests/unit/poc.c:9

  This frame has 1 object(s):
    [32, 8224) 'buf' (line 14) <== Memory access at offset 8224 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/root/work/curl/fuzz2/tests/unit/poc+0x11db40) (BuildId: 950d22dbc354c1f19b0a0459aa9b72f968a5aff4) in strlen
Shadow bytes around the buggy address:
  0xffffaae01d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xffffaae01e00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xffffaae01e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xffffaae01f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xffffaae01f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0xffffaae02000: 00 00 00 00[f3]f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 f3
  0xffffaae02080: f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 f3 f3
  0xffffaae02100: f3 f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
  0xffffaae02180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xffffaae02200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xffffaae02280: 00 00 00 00 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
==2166==ABORTING

Note that this will only affect libcurl when built with gnutls, schannel, sectransp, mbedtls (only then it’ll use Curl_extract_certinfo).

Supporting Material/References:

  • poc.c: The client code to reproduce; it simply reads a file and passes its content to Curl_extract_certinfo. The code uses a buffer on the stack, but it also works if you switch it to be a heap buffer (see the commented-out malloc call).
  • bad_cert_1.bin: The certificate with which causes the memory over-read.

Submitter info

  • I used LLVM libFuzzer to find this.
  • If this is accepted, please credit the finding to Dov Murik from Transmit Security.
  • If this is eligible for any bug bounty, please donate it to the curl project.

Impact

Attacker-controller HTTPS server can return a specially-crafted certificates that can crash libcurl-based clients when fetching the certificates and parsing them.

I couldn’t see a way where the remote attacker can actually get the content of the over-read memory bytes.

CVSS3

6.5

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

REQUIRED

Scope

UNCHANGED

Confidentiality Impact

NONE

Integrity Impact

NONE

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H

AI Score

7.2

Confidence

High

EPSS

0.001

Percentile

23.6%