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.
- Clang
sudo apt update && apt install clang
- Node.js v19.x installation
curl -fsSL https://deb.nodesource.com/setup_19.x | sudo -E bash - &&\
sudo apt-get install -y nodejs
- Make
sudo apt install make
- Clone the OpenSSL repo v3.0.6 (one prior to the patch):
git clone --branch openssl-3.0.6 https://github.com/openssl/openssl
- Copy
punycode.c
into./openssl/fuzz
:
cp punycode.c ./openssl/fuzz
-
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 -}
- Add
-
Create a test corpus in
./fuzz/corpora/punycode
:
mkdir -p ./openssl/fuzz/corpora/punycode
node index.mjs ./openssl/fuzz/corpora/punycode
-
Configure the build system as described here.
-
Build:
cd ./openssl
make clean
LDCMD=clang++ make -j4
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