From aa0faed54fb3b585bb40e4209e405c40cbaaa03e Mon Sep 17 00:00:00 2001 From: tyler92 Date: Thu, 10 Oct 2024 14:30:10 +0300 Subject: [PATCH] test: move fuzzing tests from google/oss-fuzz repository (#4719) --- CMakeLists.txt | 11 +++ Foundation/CMakeLists.txt | 4 + Foundation/fuzzing/CMakeLists.txt | 7 ++ Foundation/fuzzing/DateTimeParse.cpp | 46 +++++++++++ Foundation/fuzzing/MiscFuzzing.cpp | 95 ++++++++++++++++++++++ JSON/CMakeLists.txt | 4 + JSON/fuzzing/CMakeLists.txt | 3 + JSON/fuzzing/JsonParse.cpp | 26 ++++++ JWT/CMakeLists.txt | 4 + JWT/fuzzing/CMakeLists.txt | 3 + JWT/fuzzing/JWTDecode.cpp | 47 +++++++++++ Net/CMakeLists.txt | 3 + Net/fuzzing/CMakeLists.txt | 8 ++ Net/fuzzing/HTTPParse.cpp | 96 ++++++++++++++++++++++ Net/fuzzing/MailParse.cpp | 30 +++++++ Net/fuzzing/seed/HTTP/0001 | 8 ++ Net/fuzzing/seed/HTTP/0002 | 11 +++ Net/fuzzing/seed/HTTP/0003 | 27 +++++++ Net/fuzzing/seed/HTTP/0004 | 3 + Net/fuzzing/seed/HTTP/0005 | 4 + Net/fuzzing/seed/HTTP/0006 | 4 + Net/fuzzing/seed/HTTP/0007 | 4 + Net/fuzzing/seed/HTTP/0008 | 7 ++ Net/fuzzing/seed/HTTP/0009 | 12 +++ Net/fuzzing/seed/HTTP/0010 | 5 ++ Net/fuzzing/seed/HTTP/0011 | 6 ++ Net/fuzzing/seed/HTTP/0012 | 29 +++++++ Net/fuzzing/seed/HTTP/0013 | 22 +++++ Net/fuzzing/seed/HTTP/0014 | 2 + Net/fuzzing/seed/HTTP/0015 | 4 + Net/fuzzing/seed/Mail/0001 | 22 +++++ Net/fuzzing/seed/Mail/0002 | 30 +++++++ Net/fuzzing/seed/Mail/0003 | 9 +++ Net/fuzzing/seed/Mail/0004 | 13 +++ Net/fuzzing/seed/Mail/0005 | 9 +++ XML/CMakeLists.txt | 3 + XML/fuzzing/CMakeLists.txt | 3 + XML/fuzzing/XMLParse.cpp | 88 ++++++++++++++++++++ XML/fuzzing/xml.dict | 116 +++++++++++++++++++++++++++ build/script/oss-fuzz-build.sh | 29 +++++++ 40 files changed, 857 insertions(+) create mode 100644 Foundation/fuzzing/CMakeLists.txt create mode 100644 Foundation/fuzzing/DateTimeParse.cpp create mode 100644 Foundation/fuzzing/MiscFuzzing.cpp create mode 100644 JSON/fuzzing/CMakeLists.txt create mode 100644 JSON/fuzzing/JsonParse.cpp create mode 100644 JWT/fuzzing/CMakeLists.txt create mode 100644 JWT/fuzzing/JWTDecode.cpp create mode 100644 Net/fuzzing/CMakeLists.txt create mode 100644 Net/fuzzing/HTTPParse.cpp create mode 100644 Net/fuzzing/MailParse.cpp create mode 100644 Net/fuzzing/seed/HTTP/0001 create mode 100644 Net/fuzzing/seed/HTTP/0002 create mode 100644 Net/fuzzing/seed/HTTP/0003 create mode 100644 Net/fuzzing/seed/HTTP/0004 create mode 100644 Net/fuzzing/seed/HTTP/0005 create mode 100644 Net/fuzzing/seed/HTTP/0006 create mode 100644 Net/fuzzing/seed/HTTP/0007 create mode 100644 Net/fuzzing/seed/HTTP/0008 create mode 100644 Net/fuzzing/seed/HTTP/0009 create mode 100644 Net/fuzzing/seed/HTTP/0010 create mode 100644 Net/fuzzing/seed/HTTP/0011 create mode 100644 Net/fuzzing/seed/HTTP/0012 create mode 100644 Net/fuzzing/seed/HTTP/0013 create mode 100644 Net/fuzzing/seed/HTTP/0014 create mode 100644 Net/fuzzing/seed/HTTP/0015 create mode 100644 Net/fuzzing/seed/Mail/0001 create mode 100644 Net/fuzzing/seed/Mail/0002 create mode 100644 Net/fuzzing/seed/Mail/0003 create mode 100644 Net/fuzzing/seed/Mail/0004 create mode 100644 Net/fuzzing/seed/Mail/0005 create mode 100644 XML/fuzzing/CMakeLists.txt create mode 100644 XML/fuzzing/XMLParse.cpp create mode 100644 XML/fuzzing/xml.dict create mode 100755 build/script/oss-fuzz-build.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bbd535a76..4d8af173b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -212,6 +212,9 @@ option(ENABLE_COMPILER_WARNINGS option(ENABLE_SAMPLES "Set to OFF|ON (default is OFF) to control build of POCO samples" OFF) +option(ENABLE_FUZZING + "Set to OFF|ON (default is OFF) to control build of fuzzing targets for oss-fuzz (Clang compiler is required)" OFF) + option(POCO_UNBUNDLED "Set to OFF|ON (default is OFF) to control linking dependencies as external" OFF) @@ -226,6 +229,14 @@ else() message(STATUS "Building without tests & samples") endif() +if(ENABLE_FUZZING) + if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + message(FATAL_ERROR "ENABLE_FUZZING flag requires using Clang compiler") + else() + message(STATUS "Building fuzzing test targets with engine $ENV{LIB_FUZZING_ENGINE}") + endif() +endif() + if(POCO_UNBUNDLED) message(STATUS "Using external sqlite, zlib, pcre2, expat, libpng, ...") else() diff --git a/Foundation/CMakeLists.txt b/Foundation/CMakeLists.txt index 571d652e6e..8e0d9e8598 100644 --- a/Foundation/CMakeLists.txt +++ b/Foundation/CMakeLists.txt @@ -242,3 +242,7 @@ if(ENABLE_TESTS) endif() add_subdirectory(testsuite) endif() + +if(ENABLE_FUZZING) + add_subdirectory(fuzzing) +endif() diff --git a/Foundation/fuzzing/CMakeLists.txt b/Foundation/fuzzing/CMakeLists.txt new file mode 100644 index 0000000000..85bcf3a487 --- /dev/null +++ b/Foundation/fuzzing/CMakeLists.txt @@ -0,0 +1,7 @@ +add_executable(Foundation-datetime-fuzzer DateTimeParse.cpp) +target_link_libraries(Foundation-datetime-fuzzer PUBLIC Poco::Foundation) +set_target_properties(Foundation-datetime-fuzzer PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE}) + +add_executable(Foundation-misc-fuzzer MiscFuzzing.cpp) +target_link_libraries(Foundation-misc-fuzzer PUBLIC Poco::Foundation) +set_target_properties(Foundation-misc-fuzzer PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE}) diff --git a/Foundation/fuzzing/DateTimeParse.cpp b/Foundation/fuzzing/DateTimeParse.cpp new file mode 100644 index 0000000000..44b35b1a3b --- /dev/null +++ b/Foundation/fuzzing/DateTimeParse.cpp @@ -0,0 +1,46 @@ +#include "Poco/DateTimeParser.h" +#include "Poco/DateTimeFormat.h" +#include "Poco/DateTimeFormatter.h" + +using namespace Poco; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + const std::string input(reinterpret_cast(data), size); + + const std::string formats[] = { + DateTimeFormat::ISO8601_FORMAT, + DateTimeFormat::ISO8601_FRAC_FORMAT, + DateTimeFormat::RFC822_FORMAT, + DateTimeFormat::RFC1123_FORMAT, + DateTimeFormat::HTTP_FORMAT, + DateTimeFormat::RFC850_FORMAT, + DateTimeFormat::RFC1036_FORMAT, + DateTimeFormat::ASCTIME_FORMAT, + DateTimeFormat::SORTABLE_FORMAT, + "%m/%d/%y %h:%M %a", + "T%H:%M:%F", + }; + + int tzd = 0; + DateTime dt; + + for (const auto& format : formats) + { + DateTimeParser::tryParse(format, input, dt, tzd); + DateTimeFormatter::format(dt.timestamp(), format, tzd); + } + + dt.makeLocal(tzd); + dt.makeUTC(tzd); + + try + { + dt = DateTimeParser::parse(input, tzd); + } + catch (const std::exception&) + { + } + + return 0; +} diff --git a/Foundation/fuzzing/MiscFuzzing.cpp b/Foundation/fuzzing/MiscFuzzing.cpp new file mode 100644 index 0000000000..45712093e7 --- /dev/null +++ b/Foundation/fuzzing/MiscFuzzing.cpp @@ -0,0 +1,95 @@ +#include "Poco/URI.h" +#include "Poco/Path.h" +#include "Poco/UUID.h" +#include "Poco/UTF8String.h" +#include + +using namespace Poco; + +static void fuzzURI(FuzzedDataProvider& dataProvider) +{ + try + { + URI uri1(dataProvider.ConsumeRandomLengthString()); + URI uri2(uri1, dataProvider.ConsumeRandomLengthString()); + + URI uri3(uri2); + uri3.normalize(); + uri3.setQueryParameters(uri1.getQueryParameters()); + uri2 = uri3.toString(); + } + catch (const std::exception&) + { + } +} + +static void fuzzPath(FuzzedDataProvider& dataProvider) +{ + try + { + Path path1; + path1.tryParse(dataProvider.ConsumeRandomLengthString()); + + Path path2(path1, Path(dataProvider.ConsumeRandomLengthString())); + Path path3 = path1.absolute(); + Path path4 = Path::expand(dataProvider.ConsumeRandomLengthString()); + + const auto style1 = dataProvider.ConsumeIntegralInRange(Path::PATH_UNIX, Path::PATH_GUESS); + const auto style2 = dataProvider.ConsumeIntegralInRange(Path::PATH_UNIX, Path::PATH_GUESS); + path3.assign(path4.toString(static_cast(style1)), static_cast(style2)); + } + catch (const std::exception&) + { + } +} + +static void fuzzUUID(FuzzedDataProvider& dataProvider) +{ + try + { + UUID uuid1(dataProvider.ConsumeRandomLengthString()); + UUID uuid2(uuid1.toString()); + uuid2.tryParse(dataProvider.ConsumeRandomLengthString()); + } + catch (const std::exception&) + { + } +} + +static void fuzzUTF8String(FuzzedDataProvider& dataProvider) +{ + try + { + auto str1 = UTF8::unescape(dataProvider.ConsumeRandomLengthString()); + auto str2 = UTF8::escape(str1); + + UTF8::toUpperInPlace(str1); + UTF8::toLowerInPlace(str2); + } + catch (const std::exception&) + { + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + FuzzedDataProvider dataProvider(data, size); + + switch (dataProvider.ConsumeIntegral()) + { + case 0: + fuzzURI(dataProvider); + break; + case 1: + fuzzPath(dataProvider); + break; + case 2: + fuzzUUID(dataProvider); + break; + case 3: + fuzzUTF8String(dataProvider); + break; + } + + return 0; +} diff --git a/JSON/CMakeLists.txt b/JSON/CMakeLists.txt index 86d6ed3127..704f204de2 100644 --- a/JSON/CMakeLists.txt +++ b/JSON/CMakeLists.txt @@ -48,3 +48,7 @@ endif() if(ENABLE_TESTS) add_subdirectory(testsuite) endif() + +if(ENABLE_FUZZING) + add_subdirectory(fuzzing) +endif() diff --git a/JSON/fuzzing/CMakeLists.txt b/JSON/fuzzing/CMakeLists.txt new file mode 100644 index 0000000000..5dc66ef648 --- /dev/null +++ b/JSON/fuzzing/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(JSON-parse-fuzzer JsonParse.cpp) +target_link_libraries(JSON-parse-fuzzer PUBLIC Poco::JSON) +set_target_properties(JSON-parse-fuzzer PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE}) diff --git a/JSON/fuzzing/JsonParse.cpp b/JSON/fuzzing/JsonParse.cpp new file mode 100644 index 0000000000..fc273793d3 --- /dev/null +++ b/JSON/fuzzing/JsonParse.cpp @@ -0,0 +1,26 @@ +#include "Poco/JSON/Parser.h" + +using namespace Poco; +using namespace Poco::JSON; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + std::string json(reinterpret_cast(data), size); + Parser parser; + Dynamic::Var result; + + try + { + result = parser.parse(json); + } + catch (Exception& e) + { + return 0; + } + catch (const std::exception& e) + { + return 0; + } + + return 0; +} diff --git a/JWT/CMakeLists.txt b/JWT/CMakeLists.txt index e4d756297f..00fe4d643f 100644 --- a/JWT/CMakeLists.txt +++ b/JWT/CMakeLists.txt @@ -35,3 +35,7 @@ POCO_GENERATE_PACKAGE(JWT) if(ENABLE_TESTS) add_subdirectory(testsuite) endif() + +if(ENABLE_FUZZING) + add_subdirectory(fuzzing) +endif() diff --git a/JWT/fuzzing/CMakeLists.txt b/JWT/fuzzing/CMakeLists.txt new file mode 100644 index 0000000000..5b527de4c4 --- /dev/null +++ b/JWT/fuzzing/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(JWT-decode-fuzzer JWTDecode.cpp) +target_link_libraries(JWT-decode-fuzzer PUBLIC Poco::JWT) +set_target_properties(JWT-decode-fuzzer PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE}) diff --git a/JWT/fuzzing/JWTDecode.cpp b/JWT/fuzzing/JWTDecode.cpp new file mode 100644 index 0000000000..92e0ee1f4e --- /dev/null +++ b/JWT/fuzzing/JWTDecode.cpp @@ -0,0 +1,47 @@ +#include "Poco/JWT/Token.h" +#include "Poco/JWT/Signer.h" + +using namespace Poco; +using namespace Poco::JWT; + +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) +{ + Crypto::initializeCrypto(); + return 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + const std::string input(reinterpret_cast(data), size); + + Signer signer; + signer.addAllAlgorithms(); + signer.setHMACKey("secret"); + + try + { + // verify untrusted input + Token token; + token = signer.verify(input); + } + catch (const Exception&) + { + } + + for (const auto& algorithm : signer.getAlgorithms()) + { + try + { + // sign and verify again + Token token(input); + token.setAudience(token.getAudience()); + signer.sign(token, algorithm); + token = signer.verify(token.toString()); + } + catch (const Exception&) + { + } + } + + return 0; +} diff --git a/Net/CMakeLists.txt b/Net/CMakeLists.txt index 351228b375..2dea608a27 100644 --- a/Net/CMakeLists.txt +++ b/Net/CMakeLists.txt @@ -75,3 +75,6 @@ if(ENABLE_TESTS) add_subdirectory(testsuite) endif() +if(ENABLE_FUZZING) + add_subdirectory(fuzzing) +endif() diff --git a/Net/fuzzing/CMakeLists.txt b/Net/fuzzing/CMakeLists.txt new file mode 100644 index 0000000000..97063c5e77 --- /dev/null +++ b/Net/fuzzing/CMakeLists.txt @@ -0,0 +1,8 @@ +add_executable(Net-mail-parser-fuzzer MailParse.cpp) +target_link_libraries(Net-mail-parser-fuzzer PUBLIC Poco::Net) +set_target_properties(Net-mail-parser-fuzzer PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE}) + +add_executable(Net-http-parser-fuzzer HTTPParse.cpp) +target_link_libraries(Net-http-parser-fuzzer PUBLIC Poco::Net) +set_target_properties(Net-http-parser-fuzzer PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE}) + diff --git a/Net/fuzzing/HTTPParse.cpp b/Net/fuzzing/HTTPParse.cpp new file mode 100644 index 0000000000..bc5caff1d3 --- /dev/null +++ b/Net/fuzzing/HTTPParse.cpp @@ -0,0 +1,96 @@ +#include "Poco/MemoryStream.h" +#include "Poco/Net/EscapeHTMLStream.h" +#include "Poco/Net/HTMLForm.h" +#include "Poco/Net/HTTPCredentials.h" +#include "Poco/Net/HTTPRequest.h" +#include "Poco/Net/HTTPResponse.h" +#include "Poco/Net/OAuth10Credentials.h" +#include "Poco/Net/OAuth20Credentials.h" +#include "Poco/Net/DNS.h" +#include "Poco/NullStream.h" + +using namespace Poco; +using namespace Poco::Net; + +template +void catchExceptions(const F& func) +{ + try + { + func(); + } + catch (const std::exception&) + { + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + NullOutputStream null; + + // HTTPRequest parsing + catchExceptions( + [&] + { + MemoryInputStream stream(reinterpret_cast(data), size); + HTTPRequest request; + request.read(stream); + request.write(null); + + HTTPCredentials creds; + creds.fromURI(URI(request.getURI())); + creds.updateAuthInfo(request); + creds.updateProxyAuthInfo(request); + }); + + // HTTPResponse parsing + catchExceptions( + [&] + { + MemoryInputStream stream(reinterpret_cast(data), size); + HTTPResponse response; + response.read(stream); + response.write(null); + + HTTPRequest request(HTTPRequest::HTTP_GET, "/"); + request.setHost(DNS::encodeIDN(DNS::decodeIDN(response.get(HTTPRequest::HOST)))); + + HTTPCredentials creds; + creds.authenticate(request, response); + creds.proxyAuthenticate(request, response); + }); + + // OAuth10Credentials + catchExceptions( + [&] + { + MemoryInputStream stream(reinterpret_cast(data), size); + HTTPRequest request; + request.read(stream); + + EscapeHTMLOutputStream htmlStream(null); + HTMLForm form(request, stream); + form.prepareSubmit(request); + form.write(htmlStream); + + OAuth10Credentials oauth10(request); + oauth10.verify(request, URI(request.getURI()), form); + oauth10.authenticate(request, URI(request.getURI()), form, + request.hasToken("X-Method", "Plain") ? OAuth10Credentials::SIGN_PLAINTEXT + : OAuth10Credentials::SIGN_HMAC_SHA1); + }); + + // OAuth20Credentials + catchExceptions( + [&] + { + MemoryInputStream stream(reinterpret_cast(data), size); + HTTPRequest request; + request.read(stream); + + OAuth20Credentials oauth20(request); + oauth20.authenticate(request); + }); + + return 0; +} diff --git a/Net/fuzzing/MailParse.cpp b/Net/fuzzing/MailParse.cpp new file mode 100644 index 0000000000..4596b2ee08 --- /dev/null +++ b/Net/fuzzing/MailParse.cpp @@ -0,0 +1,30 @@ +#include "Poco/MemoryStream.h" +#include "Poco/Net/MailMessage.h" +#include "Poco/Net/MailStream.h" +#include "Poco/NullStream.h" + +using namespace Poco; +using namespace Poco::Net; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + try + { + MemoryInputStream stream(reinterpret_cast(data), size); + MailInputStream mis(stream); + MailMessage mail; + mail.read(mis); + + MailRecipient recipient(MailRecipient::CC_RECIPIENT, MailMessage::encodeWord(mail.getSender())); + mail.addRecipient(recipient); + + NullOutputStream null; + MailOutputStream mos(null); + mail.write(mos); + } + catch (const std::exception&) + { + } + + return 0; +} diff --git a/Net/fuzzing/seed/HTTP/0001 b/Net/fuzzing/seed/HTTP/0001 new file mode 100644 index 0000000000..ce25344693 --- /dev/null +++ b/Net/fuzzing/seed/HTTP/0001 @@ -0,0 +1,8 @@ +HTTP/1.0 401 Unauthorized +Server: HTTPd/0.9 +Host: localhost +Date: Sun, 10 Apr 2014 20:26:47 GMT +WWW-Authenticate: Basic realm=, charset="UTF-8" +Proxy-Authenticate: Basic realm=, charset="UTF-8" + + diff --git a/Net/fuzzing/seed/HTTP/0002 b/Net/fuzzing/seed/HTTP/0002 new file mode 100644 index 0000000000..6b13c899fe --- /dev/null +++ b/Net/fuzzing/seed/HTTP/0002 @@ -0,0 +1,11 @@ +HTTP/1.1 401 Unauthorized +Content-Length: 0 +Server: Microsoft-HTTPAPI/2.0 +WWW-Authenticate: Negotiate +WWW-Authenticate: NTLM +Proxy-Authenticate: Negotiate +Proxy-Authenticate: NTLM +Date: Tue, 10 Aug 2021 07:38:46 GMT +Proxy-Support: Session-Based-Authentication + + diff --git a/Net/fuzzing/seed/HTTP/0003 b/Net/fuzzing/seed/HTTP/0003 new file mode 100644 index 0000000000..6ce797c349 --- /dev/null +++ b/Net/fuzzing/seed/HTTP/0003 @@ -0,0 +1,27 @@ +HTTP/1.0 401 Unauthorized +Server: HTTPd/0.9 +Host: google +Date: Sun, 10 Apr 2014 20:26:47 GMT +WWW-Authenticate: Digest realm="testrealm@host.com", + qop="auth,auth-int", + nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", + opaque="5ccc069c403ebaf9f0171e9517f40e41" +Proxy-Authenticate: Digest realm="testrealm@host.com", + qop="auth,auth-int", + nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", + opaque="5ccc069c403ebaf9f0171e9517f40e41" +Content-Type: text/html +Content-Length: 153 + + + + + + Error + + +

401 Unauthorized.

+ + + + diff --git a/Net/fuzzing/seed/HTTP/0004 b/Net/fuzzing/seed/HTTP/0004 new file mode 100644 index 0000000000..92d51fe387 --- /dev/null +++ b/Net/fuzzing/seed/HTTP/0004 @@ -0,0 +1,3 @@ +HTTP/1.1 401 Unauthorized +WWW-Authenticate: NTLM + diff --git a/Net/fuzzing/seed/HTTP/0005 b/Net/fuzzing/seed/HTTP/0005 new file mode 100644 index 0000000000..3c1785ab1b --- /dev/null +++ b/Net/fuzzing/seed/HTTP/0005 @@ -0,0 +1,4 @@ +HTTP/1.1 401 Unauthorized +Host: localhost +WWW-Authenticate: NTLM TlRMTVNTUAACAAAAEAAQADgAAAAFgooCTBz0AAAAAAAAAAAAAAAAAAAAAAKAAAABYAoAAQAAAASERUVUQQ== + diff --git a/Net/fuzzing/seed/HTTP/0006 b/Net/fuzzing/seed/HTTP/0006 new file mode 100644 index 0000000000..777992f706 --- /dev/null +++ b/Net/fuzzing/seed/HTTP/0006 @@ -0,0 +1,4 @@ +GET /protected-resource HTTP/1.1 +Host: example.com +Authorization: NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw== + diff --git a/Net/fuzzing/seed/HTTP/0007 b/Net/fuzzing/seed/HTTP/0007 new file mode 100644 index 0000000000..08c70cbbe7 --- /dev/null +++ b/Net/fuzzing/seed/HTTP/0007 @@ -0,0 +1,4 @@ +GET /protected-resource HTTP/1.1 +Host: example.com +Authorization: NTLM TlRMTVNTUAADAAAAGAAYAHgAAABMAUwB0AAAABQAFACoAAAAMAAwAVAAQAAAAGAAYAGQAAABAAEABMAAAAIgAiAHAAAAAAAAAAAAAAAwAAAAAYAIgBnlgMiYmCdgYmJnPwAAAAAAAAAAAAAAAAAAAAADAB8AVAByAGkAZQBkAEUAAADAAAAA + diff --git a/Net/fuzzing/seed/HTTP/0008 b/Net/fuzzing/seed/HTTP/0008 new file mode 100644 index 0000000000..6464cdaeb2 --- /dev/null +++ b/Net/fuzzing/seed/HTTP/0008 @@ -0,0 +1,7 @@ +HTTP/2.0 200 OK +Content-Type: text/html +Set-Cookie: yummy_cookie=choco +Set-Cookie: tasty_cookie=strawberry + +[page content] + diff --git a/Net/fuzzing/seed/HTTP/0009 b/Net/fuzzing/seed/HTTP/0009 new file mode 100644 index 0000000000..79c16b5287 --- /dev/null +++ b/Net/fuzzing/seed/HTTP/0009 @@ -0,0 +1,12 @@ +POST /oauth1/access HTTP/1.1 +Host: server.example.com +Authorization: OAuth realm="Example", + oauth_consumer_key="jd83jd92dhsh93js", + oauth_token="hdk48Djdsa", + oauth_signature_method="HMAC-SHA1", + oauth_timestamp="123456789", + oauth_nonce="7d8f3e4a", + oauth_verifier="473f82d3", + oauth_signature="..." + + diff --git a/Net/fuzzing/seed/HTTP/0010 b/Net/fuzzing/seed/HTTP/0010 new file mode 100644 index 0000000000..145358ea6e --- /dev/null +++ b/Net/fuzzing/seed/HTTP/0010 @@ -0,0 +1,5 @@ +POST /resource/1/update HTTP/1.1 +Authorization: Bearer RsT5OjbzRn430zqMLgV3Ia" +Host: api.authorization-server.com + +description=Hello+World diff --git a/Net/fuzzing/seed/HTTP/0011 b/Net/fuzzing/seed/HTTP/0011 new file mode 100644 index 0000000000..e2dc22df90 --- /dev/null +++ b/Net/fuzzing/seed/HTTP/0011 @@ -0,0 +1,6 @@ +GET / HTTP/1.1 +Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== +Proxy-Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ= +Host: QWxhZGRpbjpvcGVuIHNlc2FtZQ== + + diff --git a/Net/fuzzing/seed/HTTP/0012 b/Net/fuzzing/seed/HTTP/0012 new file mode 100644 index 0000000000..70a9e03859 --- /dev/null +++ b/Net/fuzzing/seed/HTTP/0012 @@ -0,0 +1,29 @@ +POST /cgi-bin/qtest HTTP/1.1 +Host: aram +User-Agent: Mozilla/5.0 Gecko/2009042316 Firefox/3.0.10 +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Accept-Language: en-us,en;q=0.5 +Accept-Encoding: gzip,deflate +Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 +Keep-Alive: 300 +Connection: keep-alive +Referer: http://aram/~martind/banner.htm +Content-Type: multipart/form-data; boundary=2a8ae6ad-f4ad-4d9a-a92c-6d217011fe0f +Content-Length: 514 + +--2a8ae6ad-f4ad-4d9a-a92c-6d217011fe0f +Content-Disposition: form-data; name="datafile1"; filename="r.gif" +Content-Type: image/gif + +GIF87a.............,...........D..; +--2a8ae6ad-f4ad-4d9a-a92c-6d217011fe0f +Content-Disposition: form-data; name="datafile2"; filename="g.gif" +Content-Type: image/gif + +GIF87a.............,...........D..; +--2a8ae6ad-f4ad-4d9a-a92c-6d217011fe0f +Content-Disposition: form-data; name="datafile3"; filename="b.gif" +Content-Type: image/gif + +GIF87a.............,...........D..; +--2a8ae6ad-f4ad-4d9a-a92c-6d217011fe0f-- diff --git a/Net/fuzzing/seed/HTTP/0013 b/Net/fuzzing/seed/HTTP/0013 new file mode 100644 index 0000000000..4494d60460 --- /dev/null +++ b/Net/fuzzing/seed/HTTP/0013 @@ -0,0 +1,22 @@ +GET /dir/index.html HTTP/1.0 +Host: localhost +Authorization: Digest username="Mufasa", + realm="testrealm@host.com", + nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", + uri="/dir/index.html", + qop=auth, + nc=00000001, + cnonce="0a4f113b", + response="6629fae49393a05397450978507c4ef1", + opaque="5ccc069c403ebaf9f0171e9517f40e41" + +Proxy-Authorization: Digest username="Mufasa", + realm="testrealm@host.com", + nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", + uri="/dir/index.html", + qop=auth, + nc=00000001, + cnonce="0a4f113b", + response="6629fae49393a05397450978507c4ef1", + opaque="5ccc069c403ebaf9f0171e9517f40e41" + diff --git a/Net/fuzzing/seed/HTTP/0014 b/Net/fuzzing/seed/HTTP/0014 new file mode 100644 index 0000000000..fc047316d8 --- /dev/null +++ b/Net/fuzzing/seed/HTTP/0014 @@ -0,0 +1,2 @@ +GET / HTTP/1.1 +Header: =?UTF32?B?xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxe///////////xxxxxxxxxxx?= diff --git a/Net/fuzzing/seed/HTTP/0015 b/Net/fuzzing/seed/HTTP/0015 new file mode 100644 index 0000000000..977142d5ed --- /dev/null +++ b/Net/fuzzing/seed/HTTP/0015 @@ -0,0 +1,4 @@ +GET http://example.com/ HTTP/1.1 +Host: example.com +Proxy-Authorization: NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw== + diff --git a/Net/fuzzing/seed/Mail/0001 b/Net/fuzzing/seed/Mail/0001 new file mode 100644 index 0000000000..9962941def --- /dev/null +++ b/Net/fuzzing/seed/Mail/0001 @@ -0,0 +1,22 @@ +From: sender@example.com +To: recipient@example.com +Subject: =?CP1251?B?T2zpcg==?= +Content-Type: multipart/alternative; boundary="boundary-string" + +--your-boundary +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: quoted-printable +Content-Disposition: inline + +Plain text email goes here! +This is the fallback if email client does not support HTML + +--boundary-string +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: quoted-printable +Content-Disposition: inline + +

This is the HTML Section!

+

This is what displays in most modern email clients

+ +--boundary-string-- diff --git a/Net/fuzzing/seed/Mail/0002 b/Net/fuzzing/seed/Mail/0002 new file mode 100644 index 0000000000..2fcff4ada6 --- /dev/null +++ b/Net/fuzzing/seed/Mail/0002 @@ -0,0 +1,30 @@ +From: Some One +To: Someone Else +Subject: =?MacChineseTrad?B?T2zpcg==?= +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary=zxnrbl + +This is the preamble. +--zxnrbl +Content-Type: multipart/alternative; boundary=xyzzy + +This is the nested preamble. +--xyzzy +Content-Type: text/plain + +Hello! +--xyzzy +Content-Type: text/html + +

Hello!

+--xyzzy-- +This is the nested epilogue. +--zxnrbl +Content-Type: text/plain +Content-Disposition: attachment; filename="attachment.txt" + +This is the attachment. +--zxnrbl-- +This is the epilogue. + + diff --git a/Net/fuzzing/seed/Mail/0003 b/Net/fuzzing/seed/Mail/0003 new file mode 100644 index 0000000000..2cc52eabab --- /dev/null +++ b/Net/fuzzing/seed/Mail/0003 @@ -0,0 +1,9 @@ +From: sender@example.com +To: recipient@example.com +Subject: =?ISO-8859-1?B?T2zpcg==?= +Date: Tue, 1 Oct 2024 10:00:00 +0000 +MIME-Version: 1.0 +Content-Type: text/plain; charset="ISO-8859-1" +Content-Transfer-Encoding: 7bit + +Hello diff --git a/Net/fuzzing/seed/Mail/0004 b/Net/fuzzing/seed/Mail/0004 new file mode 100644 index 0000000000..2723de126d --- /dev/null +++ b/Net/fuzzing/seed/Mail/0004 @@ -0,0 +1,13 @@ +From: sender@example.com +To: recipient@example.com +Content-Type: multipart/mixed; boundary="boundary" + +--boundary +Content-Type: text/plain; charset="UTF-8" +Content-Transfer-Encoding: base64 + +SGVsbG8gdGhlcmUsCgpUaGlzIGlzIGEgc2FtcGxlIGVtYWlsIHdpdGggYmFzZTY0IGVuY29kaW5n +IGFuZCBhbiBhdHRhY2htZW50LgoKLS0gU2VuZGVy + +--boundary-- + diff --git a/Net/fuzzing/seed/Mail/0005 b/Net/fuzzing/seed/Mail/0005 new file mode 100644 index 0000000000..dae2863670 --- /dev/null +++ b/Net/fuzzing/seed/Mail/0005 @@ -0,0 +1,9 @@ +From: sender@example.com +To: recipient@example.com +Subject: =?UTF-8?B?44GT44KT44Gr44Gh44Gv?= +Date: Tue, 1 Oct 2024 10:00:00 +0000 +MIME-Version: 1.0 +Content-Type: text/plain; charset="UTF-8" +Content-Transfer-Encoding: 7bit + +Hello diff --git a/XML/CMakeLists.txt b/XML/CMakeLists.txt index 448e5017a9..cf6625015e 100644 --- a/XML/CMakeLists.txt +++ b/XML/CMakeLists.txt @@ -73,3 +73,6 @@ if(ENABLE_TESTS) add_subdirectory(testsuite) endif() +if(ENABLE_FUZZING) + add_subdirectory(fuzzing) +endif() diff --git a/XML/fuzzing/CMakeLists.txt b/XML/fuzzing/CMakeLists.txt new file mode 100644 index 0000000000..201487f580 --- /dev/null +++ b/XML/fuzzing/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(XML-parse-fuzzer XMLParse.cpp) +target_link_libraries(XML-parse-fuzzer PUBLIC Poco::XML) +set_target_properties(XML-parse-fuzzer PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE}) diff --git a/XML/fuzzing/XMLParse.cpp b/XML/fuzzing/XMLParse.cpp new file mode 100644 index 0000000000..846eccb70a --- /dev/null +++ b/XML/fuzzing/XMLParse.cpp @@ -0,0 +1,88 @@ +#include "Poco/AutoPtr.h" +#include "Poco/DOM/DOMParser.h" +#include "Poco/DOM/Document.h" +#include "Poco/SAX/DefaultHandler.h" +#include "Poco/SAX/SAXParser.h" +#include "Poco/XML/XMLStreamParser.h" + +using namespace Poco; +using namespace Poco::XML; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + std::string xml(reinterpret_cast(data), size); + + // SAX Parser + + SAXParser saxParser; + std::uint8_t saxFeatures = size > 0 ? data[size - 1] : 0; + + DefaultHandler defHandler; + saxParser.setContentHandler(&defHandler); + saxParser.setDTDHandler(&defHandler); + saxParser.setErrorHandler(&defHandler); + saxParser.setEntityResolver(&defHandler); + + for (const auto feature : { + XMLReader::FEATURE_EXTERNAL_GENERAL_ENTITIES, + XMLReader::FEATURE_EXTERNAL_PARAMETER_ENTITIES, + XMLReader::FEATURE_NAMESPACES, + XMLReader::FEATURE_NAMESPACE_PREFIXES, + SAXParser::FEATURE_PARTIAL_READS, + }) + { + saxParser.setFeature(feature, saxFeatures & 0x01); + saxFeatures >>= 1; + } + + try + { + saxParser.parseString(xml); + } + catch (const std::exception&) + { + } + + // DOM Parser + + DOMParser domParser; + std::uint8_t domFeatures = size > 0 ? data[size - 1] : 0; + + for (const auto feature : { + XMLReader::FEATURE_EXTERNAL_GENERAL_ENTITIES, + XMLReader::FEATURE_EXTERNAL_PARAMETER_ENTITIES, + XMLReader::FEATURE_NAMESPACES, + XMLReader::FEATURE_NAMESPACE_PREFIXES, + DOMParser::FEATURE_FILTER_WHITESPACE, + }) + { + domParser.setFeature(feature, domFeatures & 0x01); + domFeatures >>= 1; + } + + try + { + Poco::AutoPtr doc = domParser.parseString(xml); + } + catch (const std::exception&) + { + } + + // Stream Parser + + std::istringstream stream(xml); + + try + { + XMLStreamParser streamParser(stream, "fuzz"); + for (XMLStreamParser::EventType e : streamParser) + { + streamParser.getQName().toString(); + } + } + catch (const std::exception&) + { + } + + return 0; +} diff --git a/XML/fuzzing/xml.dict b/XML/fuzzing/xml.dict new file mode 100644 index 0000000000..2ff824a6a6 --- /dev/null +++ b/XML/fuzzing/xml.dict @@ -0,0 +1,116 @@ +attr_encoding=" encoding=\"1\"" +attr_generic=" a=\"1\"" +attr_href=" href=\"1\"" +attr_standalone=" standalone=\"no\"" +attr_version=" version=\"1\"" +attr_xml_base=" xml:base=\"1\"" +attr_xml_id=" xml:id=\"1\"" +attr_xml_lang=" xml:lang=\"1\"" +attr_xml_space=" xml:space=\"1\"" +attr_xmlns=" xmlns=\"1\"" + +entity_builtin="<" +entity_decimal="" +entity_external="&a;" +entity_hex="" + +# keywords +"ANY" +"ATTLIST" +"CDATA" +"DOCTYPE" +"ELEMENT" +"EMPTY" +"ENTITIES" +"ENTITY" +"FIXED" +"ID" +"IDREF" +"IDREFS" +"IGNORE" +"IMPLIED" +"INCLUDE" +"NDATA" +"NMTOKEN" +"NMTOKENS" +"NOTATION" +"PCDATA" +"PUBLIC" +"REQUIRED" +"SYSTEM" + +# Various tag parts +"<" +">" +"/>" +"" +"" +"[]" +"]]" +"" +"\"\"" +"''" +"=\"\"" +"=''" + +# DTD +"" +tag_open="" +tag_open_close="" + + +"" +"http://docboo" +"http://www.w" +"he30" +"he2" +"IET" +"FDF-10" +"aDUCS-4OPveb:" +"a>" +"UT" +"xMl" +"/usr/share/sg" +"ha07" +"http://www.oa" +"cle" diff --git a/build/script/oss-fuzz-build.sh b/build/script/oss-fuzz-build.sh new file mode 100755 index 0000000000..5eb313632a --- /dev/null +++ b/build/script/oss-fuzz-build.sh @@ -0,0 +1,29 @@ +#!/bin/bash -eu + +mkdir -p cmake-build +cd cmake-build + +cmake -DBUILD_SHARED_LIBS=OFF -DENABLE_TESTS=OFF -DENABLE_FUZZING=ON \ + -DENABLE_ACTIVERECORD=OFF -DENABLE_PAGECOMPILER=OFF \ + -DENABLE_PAGECOMPILER_FILE2PAGE=OFF -DENABLE_DATA_SQLITE=OFF \ + -DENABLE_REDIS=OFF -DENABLE_MONGODB=OFF -DENABLE_PROMETHEUS=OFF \ + -DENABLE_ACTIVERECORD_COMPILER=OFF \ + .. + +make -j$(nproc) + +# Copy binaries with preserving historical names +cp bin/JSON-parse-fuzzer $OUT/json_parser_fuzzer +cp bin/XML-parse-fuzzer $OUT/xml_parser_fuzzer +cp bin/Foundation-datetime-fuzzer $OUT/date_time_fuzzer +cp bin/Foundation-misc-fuzzer $OUT/foundation_misc_fuzzer +cp bin/JWT-decode-fuzzer $OUT/jwt_decode_fuzzer +cp bin/Net-mail-parser-fuzzer $OUT/mail_message_fuzzer +cp bin/Net-http-parser-fuzzer $OUT/http_message_fuzzer + +# Seed corpus +zip -q -r -j $OUT/mail_message_fuzzer_seed_corpus.zip $SRC/poco/Net/fuzzing/seed/Mail +zip -q -r -j $OUT/http_message_fuzzer_seed_corpus.zip $SRC/poco/Net/fuzzing/seed/HTTP + +# Dictionaries +cp $SRC/poco/XML/fuzzing/xml.dict $OUT/xml_parser_fuzzer.dict