diff --git a/regress/fuzzers/zip_read_encrypted_file_fuzzer.cc b/regress/fuzzers/zip_read_encrypted_file_fuzzer.cc new file mode 100644 index 000000000..1362b9449 --- /dev/null +++ b/regress/fuzzers/zip_read_encrypted_file_fuzzer.cc @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" +#endif + +/** +This fuzzer target simulates the process of handling encrypted files within a ZIP archive . +**/ + +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + zip_source_t* src; + zip_t* za; + zip_error_t error; + char buf[32768]; + zip_int64_t i, n; + zip_file_t* f; + + + if ((src = zip_source_buffer_create(data, size, 0, &error)) == NULL) { + zip_error_fini(&error); + return 0; + } + + if ((za = zip_open_from_source(src, 0, &error)) == NULL) { + zip_source_free(src); + zip_error_fini(&error); + return 0; + } + + int file_index = zip_name_locate(za, "file", 0); + + if (file_index < 0) { + std::cerr << "Failed to locate encrypted file in ZIP archive" << std::endl; + zip_close(za); + return 1; + } + + zip_file_t *file = zip_fopen_index_encrypted(za, file_index, 0, "secretpassword"); + + if (!file) { + std::cerr << "Failed to open encrypted file for reading" << std::endl; + zip_close(za); + return 1; + } + + + zip_fclose(file); + zip_close(za); + + return 0; +} diff --git a/regress/fuzzers/zip_read_file_fuzzer.cc b/regress/fuzzers/zip_read_file_fuzzer.cc new file mode 100644 index 000000000..f255160e2 --- /dev/null +++ b/regress/fuzzers/zip_read_file_fuzzer.cc @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include + +std::string random_string(size_t length); + +#ifdef __cplusplus +extern "C" +#endif + +/** +This fuzzing target takes input data, creates a ZIP archive from it, checks the archive's consistency, +and iterates over the entries in the archive, reading data from each entry. +**/ + +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + zip_source_t* src; + zip_t* za; + zip_error_t error; + char buf[32768]; + zip_int64_t i, n; + zip_file_t* f; + + std::string name = random_string(20) + ".zip"; + + std::ofstream outfile(name, std::ios::binary); + + if (outfile.is_open()) { + outfile.write(reinterpret_cast(data), size); + outfile.close(); + + za = zip_open(name.c_str(), 0, NULL); + n = zip_get_num_entries(za, 0); + for (i = 0; i < n; i++) { + f = zip_fopen_index(za, i, 0); + if (f == NULL) { + continue; + } + + while (zip_fread(f, buf, sizeof(buf)) > 0) { + ; + } + zip_fclose(f); + + } + zip_close(za); + std::remove(name.c_str()); + + } + else { + std::cerr << "Unable to open the file." << std::endl; + } + + return 0; +} + +std::string random_string(size_t length) +{ + auto randchar = []() -> char { + const char charset[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + const size_t max_index = (sizeof(charset) - 1); + return charset[rand() % max_index]; + }; + std::string str(length, 0); + std::generate_n(str.begin(), length, randchar); + return str; +} diff --git a/regress/zip_read_fuzzer.cc b/regress/fuzzers/zip_read_fuzzer.cc old mode 100644 new mode 100755 similarity index 100% rename from regress/zip_read_fuzzer.cc rename to regress/fuzzers/zip_read_fuzzer.cc diff --git a/regress/fuzzers/zip_write_encrypt_aes256_file_fuzzer.cc b/regress/fuzzers/zip_write_encrypt_aes256_file_fuzzer.cc new file mode 100644 index 000000000..c6ea4f043 --- /dev/null +++ b/regress/fuzzers/zip_write_encrypt_aes256_file_fuzzer.cc @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include + +std::string random_string(size_t length); + +#ifdef __cplusplus +extern "C" +#endif + +/** +This fuzzing target takes input data, creates a ZIP archive, load it to a buffer, adds a file to it +with AES-256 encryption and a specified password, and then closes and removes the archive. + +The purpose of this fuzzer is to test security of ZIP archive handling and encryption in the libzip +by subjecting it to various inputs, including potentially malicious or malformed data of different file types. +**/ + +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + zip_source_t* src; + zip_t* za; + char buf[32768]; + zip_int64_t i, n; + zip_file_t* f; + + std::string path = random_string(20) + "_aes256"+ ".zip"; + const char *password = random_string(20).c_str(); + const char * file = random_string(20).c_str(); + int error = 0; + struct zip *archive = zip_open(path.c_str(), ZIP_CREATE, &error); + + if(error) + return -1; + + struct zip_source *source = zip_source_buffer(archive, data, size, 0); + if(source == NULL){ + printf("failed to create source buffer. %s\n",zip_strerror(archive)); + return -1; + } + + int index = (int)zip_file_add(archive, file, source, ZIP_FL_OVERWRITE); + if(index < 0){ + printf("failed to add file to archive: %s\n",zip_strerror(archive)); + return -1; + } + zip_file_set_encryption(archive, index, ZIP_EM_AES_256, password); + zip_close(archive); + std::remove(path.c_str()); + + return 0; +} + +std::string random_string(size_t length) +{ + auto randchar = []() -> char { + const char charset[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + const size_t max_index = (sizeof(charset) - 1); + return charset[rand() % max_index]; + }; + std::string str(length, 0); + std::generate_n(str.begin(), length, randchar); + return str; +} diff --git a/regress/fuzzers/zip_write_encrypt_pkware_file_fuzzer.cc b/regress/fuzzers/zip_write_encrypt_pkware_file_fuzzer.cc new file mode 100644 index 000000000..b76a6de62 --- /dev/null +++ b/regress/fuzzers/zip_write_encrypt_pkware_file_fuzzer.cc @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include + +std::string random_string(size_t length); + +#ifdef __cplusplus +extern "C" +#endif + +/** +This fuzzing target takes input data, creates a ZIP archive, load it to a buffer, adds a file to it +with traditional PKWARE encryption and a specified password, and then closes and removes the archive. + +The purpose of this fuzzer is to test security of ZIP archive handling and encryption in the libzip +by subjecting it to various inputs, including potentially malicious or malformed data of different file types. +**/ + +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + zip_source_t* src; + zip_t* za; + char buf[32768]; + zip_int64_t i, n; + zip_file_t* f; + + std::string path = random_string(20) + "_pkware"+ ".zip"; + const char *password = random_string(20).c_str(); + const char * file = random_string(20).c_str(); + int error = 0; + struct zip *archive = zip_open(path.c_str(), ZIP_CREATE, &error); + + if(error) + return -1; + + struct zip_source *source = zip_source_buffer(archive, data, size, 0); + if(source == NULL){ + printf("failed to create source buffer. %s\n",zip_strerror(archive)); + return -1; + } + + int index = (int)zip_file_add(archive, file, source, ZIP_FL_OVERWRITE); + if(index < 0){ + printf("failed to add file to archive: %s\n",zip_strerror(archive)); + return -1; + } + zip_file_set_encryption(archive, index, ZIP_EM_TRAD_PKWARE,/* Password to encrypt file */ password); + zip_close(archive); + std::remove(path.c_str()); + + return 0; +} + +std::string random_string(size_t length) +{ + auto randchar = []() -> char { + const char charset[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + const size_t max_index = (sizeof(charset) - 1); + return charset[rand() % max_index]; + }; + std::string str(length, 0); + std::generate_n(str.begin(), length, randchar); + return str; +} diff --git a/regress/ossfuzz.sh b/regress/ossfuzz.sh index 01e41708c..04ad2b086 100755 --- a/regress/ossfuzz.sh +++ b/regress/ossfuzz.sh @@ -18,18 +18,43 @@ # This script is meant to be run by # https://github.com/google/oss-fuzz/blob/master/projects/libzip/Dockerfile + mkdir build cd build -cmake -DBUILD_SHARED_LIBS=OFF -DENABLE_GNUTLS=OFF -DENABLE_MBEDTLS=OFF -DENABLE_OPENSSL=OFF -DBUILD_TOOLS=OFF -DENABLE_LZMA=OFF .. +cmake -DBUILD_SHARED_LIBS=OFF -DENABLE_GNUTLS=OFF -DENABLE_MBEDTLS=OFF -DENABLE_OPENSSL=ON -DBUILD_TOOLS=OFF -DENABLE_LZMA=OFF -DHAVE_CRYPTO=ON .. make -j$(nproc) $CXX $CXXFLAGS -std=c++11 -I. -I../lib \ - $SRC/libzip/regress/zip_read_fuzzer.cc \ + $SRC/libzip/regress/fuzzers/zip_read_fuzzer.cc \ -o $OUT/zip_read_fuzzer \ - $LIB_FUZZING_ENGINE $SRC/libzip/build/lib/libzip.a -lz + $LIB_FUZZING_ENGINE $SRC/libzip/build/lib/libzip.a -lz -v -lssl -lcrypto + +$CXX $CXXFLAGS -std=c++11 -I. -I../lib \ + $SRC/libzip/regress/fuzzers/zip_write_encrypt_aes256_file_fuzzer.cc \ + -o $OUT/zip_write_encrypt_aes256_file_fuzzer \ + $LIB_FUZZING_ENGINE $SRC/libzip/build/lib/libzip.a -lz -v -lssl -lcrypto -find $SRC/libzip/regress -name "*.zip" | \ +$CXX $CXXFLAGS -std=c++11 -I. -I../lib \ + $SRC/libzip/regress/fuzzers/zip_write_encrypt_pkware_file_fuzzer.cc \ + -o $OUT/zip_write_encrypt_pkware_file_fuzzer \ + $LIB_FUZZING_ENGINE $SRC/libzip/build/lib/libzip.a -lz -v -lssl -lcrypto + +$CXX $CXXFLAGS -std=c++11 -I. -I../lib \ + $SRC/libzip/regress/fuzzers/zip_read_encrypted_file_fuzzer.cc \ + -o $OUT/zip_read_encrypted_archive_fuzzer \ + $LIB_FUZZING_ENGINE $SRC/libzip/build/lib/libzip.a -lz -v -lssl -lcrypto + +$CXX $CXXFLAGS -std=c++11 -I. -I../lib \ + $SRC/libzip/regress/fuzzers/zip_read_file_fuzzer.cc \ + -o $OUT/zip_read_file_fuzzer \ + $LIB_FUZZING_ENGINE $SRC/libzip/build/lib/libzip.a -lz -v -lssl -lcrypto + +find $SRC/libzip/regress -name "*zip" -not -name "*fuzzer_seed_corpus*" | \ xargs zip $OUT/zip_read_fuzzer_seed_corpus.zip -cp $SRC/libzip/regress/zip_read_fuzzer.dict $OUT/ +cp $SRC/libzip/regress/zip_write_encrypt_aes256_file_fuzzer_seed_corpus.zip $OUT/ +cp $SRC/libzip/regress/zip_write_encrypt_aes256_file_fuzzer_seed_corpus.zip $OUT/zip_write_encrypt_pkware_file_fuzzer_seed_corpus.zip +cp $SRC/libzip/regress/zip_read_encrypted_file_fuzzer_seed_corpus.zip $OUT/ +cp $SRC/libzip/regress/zip_read_fuzzer.dict $OUT/ +cp $OUT/zip_read_fuzzer_seed_corpus.zip $OUT/zip_read_file_fuzzer_seed_corpus.zip \ No newline at end of file diff --git a/regress/zip_read_encrypted_file_fuzzer_seed_corpus.zip b/regress/zip_read_encrypted_file_fuzzer_seed_corpus.zip new file mode 100644 index 000000000..739207c60 Binary files /dev/null and b/regress/zip_read_encrypted_file_fuzzer_seed_corpus.zip differ diff --git a/regress/zip_write_encrypt_aes256_file_fuzzer_seed_corpus.zip b/regress/zip_write_encrypt_aes256_file_fuzzer_seed_corpus.zip new file mode 100644 index 000000000..431d73877 Binary files /dev/null and b/regress/zip_write_encrypt_aes256_file_fuzzer_seed_corpus.zip differ