HexBrain

curl · Report #2629968

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

Validstatus
lowseverity
53upvotes
1 Aug 2024disclosed

How it was found

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.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original