OpenSSL v3.0.7 CVEs Fuzzing

This repo is meant to show how OpenSSL v3.0.7 latest CVE-2022-3602 can be found using libFuzzer. OpenSSL has built-in fuzzing support in ./fuzz as part of the oss-fuzz project. We'll use it and add our own test harness.

Dependencies

  1. Clang
    sudo apt update && apt install clang
  1. Node.js v19.x installation
    curl -fsSL https://deb.nodesource.com/setup_19.x | sudo -E bash - &&\
    sudo apt-get install -y nodejs
  1. Make
    sudo apt install make

Setup

  1. Clone the OpenSSL repo v3.0.6 (one prior to the patch):
    git clone --branch openssl-3.0.6 https://github.com/openssl/openssl
  1. Copy punycode.c into ./openssl/fuzz:
    cp punycode.c ./openssl/fuzz
  1. Modify ./openssl/fuzz/build.info:

    • Add punycode to the list of programs:
    PROGRAMS{noinst}=asn1 asn1parse bignum bndiv client conf crl server x509 punycode
    
    • Add a build config for the compilation:
    SOURCE[punycode]=punycode.c driver.c
    INCLUDE[punycode]=../include {- $ex_inc -}
    DEPEND[punycode]=../libcrypto ../libssl {- $ex_lib -}
    
  2. Create a test corpus in ./fuzz/corpora/punycode:

    mkdir -p ./openssl/fuzz/corpora/punycode
    node index.mjs ./openssl/fuzz/corpora/punycode
  1. Configure the build system as described here.

  2. Build:

    cd ./openssl
    make clean
    LDCMD=clang++ make -j4

Running the fuzzer

To run the fuzzer:

    CORES=$(grep -c ^processor /proc/cpuinfo)
    ./openssl/fuzz/punycode -workers=$CORES -jobs=$CORES -dict=punycode.dict ./openssl/fuzz/corpora/punycode

A sample crash should look like:

==9024==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffeb247ede0 at pc 0x5615d1499782 bp 0x7ffeb247da50 sp 0x7ffeb247d220
WRITE of size 264 at 0x7ffeb247ede0 thread T0
    #0 0x5615d1499781 in __asan_memmove (/home/user/openssl/fuzz/punycode+0xd7d781) (BuildId: 546d1cbf454c87a04c514633876bd5307eab38b2)
    #1 0x5615d155c023 in ossl_punycode_decode /home/user/openssl/crypto/punycode.c:188:9
    #2 0x5615d14d76de in FuzzerTestOneInput /home/user/openssl/fuzz/punycode.c:42:11
    #3 0x5615d14d73e4 in LLVMFuzzerTestOneInput /home/user/openssl/fuzz/driver.c:28:12
    #4 0x5615d14ee823 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/home/user/openssl/fuzz/punycode+0xdd2823) (BuildId: 546d1cbf454c87a04c514633876bd5307eab38b2)
    #5 0x5615d14edf79 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) (/home/user/openssl/fuzz/punycode+0xdd1f79) (BuildId: 546d1cbf454c87a04c514633876bd5307eab38b2)
    #6 0x5615d14ef769 in fuzzer::Fuzzer::MutateAndTestOne() (/home/user/openssl/fuzz/punycode+0xdd3769) (BuildId: 546d1cbf454c87a04c514633876bd5307eab38b2)
    #7 0x5615d14f02e5 in fuzzer::Fuzzer::Loop(std::vector<fuzzer::SizedFile, std::allocator<fuzzer::SizedFile> >&) (/home/user/openssl/fuzz/punycode+0xdd42e5) (BuildId: 546d1cbf454c87a04c514633876bd5307eab38b2)
    #8 0x5615d14ddd42 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/home/user/openssl/fuzz/punycode+0xdc1d42) (BuildId: 546d1cbf454c87a04c514633876bd5307eab38b2)
    #9 0x5615d14d7822 in main (/home/user/openssl/fuzz/punycode+0xdbb822) (BuildId: 546d1cbf454c87a04c514633876bd5307eab38b2)
    #10 0x7f3f2bf4bd8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: 69389d485a9793dbe873f0ea2c93e02efaa9aa3d)
    #11 0x7f3f2bf4be3f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e3f) (BuildId: 69389d485a9793dbe873f0ea2c93e02efaa9aa3d)
    #12 0x5615d1417104 in _start (/home/user/openssl/fuzz/punycode+0xcfb104) (BuildId: 546d1cbf454c87a04c514633876bd5307eab38b2)

Address 0x7ffeb247ede0 is located in stack of thread T0 at offset 4128 in frame
    #0 0x5615d14d751f in FuzzerTestOneInput /home/user/openssl/fuzz/punycode.c:39

  This frame has 2 object(s):
    [32, 4128) 'output_buf' (line 40)
    [4256, 4260) 'bsize' (line 41) <== Memory access at offset 4128 partially underflows 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 (/home/user/openssl/fuzz/punycode+0xd7d781) (BuildId: 546d1cbf454c87a04c514633876bd5307eab38b2) in __asan_memmove
Shadow bytes around the buggy address:
  0x100056487d60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100056487d70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100056487d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100056487d90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100056487da0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x100056487db0: 00 00 00 00 00 00 00 00 00 00 00 00[f2]f2 f2 f2
  0x100056487dc0: f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 04 f3 f3 f3
  0x100056487dd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100056487de0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100056487df0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100056487e00: 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
==9024==ABORTING
MS: 1 EraseBytes-; base unit: dcfa4dd109a8a3a137a0fbf0d1ba0213f14e7478
artifact_prefix='./'; Test unit written to ./crash-7abb0df0c999d6c5032aa2d7d442c7cbc4805729