diff --git a/cve/openssl/2022/CVE-2022-3786/Makefile b/cve/openssl/2022/CVE-2022-3786/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fc45cfd37493784d9d603ba8a3b2c34f8e9e7e68 --- /dev/null +++ b/cve/openssl/2022/CVE-2022-3786/Makefile @@ -0,0 +1,20 @@ +ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) +CC = afl-gcc-fast +CXX= afl-g++-fast +INCLUDE = -Iopenssl/include -Iopenssl/test +CFLAGS = -m32 -fno-stack-protector -ggdb -Wl,-z,relro +LDFLAGS = -L$(ROOT_DIR)/openssl -l:libcrypto.so.3 -l:libcrypto.a + +.DEFAULT_GOAL := harness + +# What we'll actually use for fuzzing. +harness: harness.c + AFL_USE_ASAN=1 $(CC) -o $@ $< $(CFLAGS) $(INCLUDE) $(LDFLAGS) + +# Confirm that the vulnerability is present. +confirm-vulnerability: confirm-vulnerability.c + AFL_USE_ASAN=1 $(CC) -o $@ $< $(CFLAGS) $(INCLUDE) $(LDFLAGS) + +clean: + rm -f harness + rm -f confirm-vulnerability \ No newline at end of file diff --git a/cve/openssl/2022/CVE-2022-3786/README.md b/cve/openssl/2022/CVE-2022-3786/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a43b6cf2cf3cf69056b15c285944e03664f1116a --- /dev/null +++ b/cve/openssl/2022/CVE-2022-3786/README.md @@ -0,0 +1,75 @@ +# Fuzzing OpenSSL + +This repository has a companion blog post titled "Finding CVE-2022-3786 (openssl) with Mayhem" at https://www.seandeaton.com. + +## tl;dr + +All of this is taken care of for you with the included Dockerfile (also on DockerHub). You can run it like so: + +```shell +# Build the container +docker build --tag openssl-cve-2022-3768 . +# Or if you just want to pull down the existing one: +TODO +# Ensure that you're in this project's root directory (ie you can see ./output/) +# Mount the ./input/ directory to the containers /input. This is for fuzz input. +# This is Linux specific, Windows I think has %CD% in lieu of $(pwd)? +docker run --interactive --tty --volume $(pwd)/input:/input +``` + +The entrypoint of the container is to just run `afl` so you can get started +fuzzing immediately. To override this behavior, append `/bin/bash` to the end +of the `docker run` line. + +## Getting a Vulnerable Version + +The last commit that includes the vulnerability is commit SHA `3b421ebc64c7b52f1b9feb3812bdc7781c784332` from November 1st, 2022. It was fixed in commit SHA `680e65b94c916af259bfdc2e25f1ab6e0c7a97d6`. We can get the vulnerable version easily with `git`: + +```shell +# Clone the repository. +git clone git://git.openssl.org/openssl.git +# Change into the working directory. +cd openssl +# Detach HEAD from origin to examine the code as it was when it was vulnerable. +git checkout 3b421ebc64c7b52f1b9feb3812bdc7781c784332 +``` + +## Compiling + +For compilation, we use AFL's gcc compiler (because I kept getting undefined +references with `clang`). Because of the small buffer overflow +offset, we also want to use address sanitization (ASAN), enabled with AFL's +environment variable `AFL_USE_ASAN`. Given ASAN's use of large amounts of +memory, we also need to restrict the address space which we can do by compiling +the program for a 32-bit architecture. More detail [here][afl-asan]. + +OpenSSL's configuration for 32-bit takes in the flags `-m32` and +`linux-generic32`. The `compile.sh` script does this for you. + +```shell +# Configuration +AFL_USE_ASAN=1 CC=afl-gcc-fast CXX=afl-g++-fast ./Configure -m32 linux-generic32 +# Make +AFL_USE_ASAN=1 CC=afl-gcc-fast CXX=afl-g++-fast CFLAGS="-m32" CXXFLAGS="-m32" make +``` + +This could take awhile given your system's resources. After compilation, we need +to compile our harness. A Makefile is given. + +```shell +# Compile the harness. +$ make harness +# Run the harness. +$ ./harness input/seed0.txt +ossl_a2ulabel returned: 1 +``` + +And there you go, you can get started fuzzing the `ossl_a2ulabel` in `openssl`. +With AFL the command looks something like the following (or just use the +included `run.sh` script). + +```shell +afl-fuzz -i /input -o /output /harness/harness @@ +``` + +[afl-asan]: https://afl-1.readthedocs.io/en/latest/notes_for_asan.html diff --git a/cve/openssl/2022/CVE-2022-3786/compile.sh b/cve/openssl/2022/CVE-2022-3786/compile.sh new file mode 100644 index 0000000000000000000000000000000000000000..61843307004cc5dfbe4f94639db8be6831e3d907 --- /dev/null +++ b/cve/openssl/2022/CVE-2022-3786/compile.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +# Change directories into openssl. +cd ./openssl + +# Ensure we're on the vulnerable version. +git checkout eec0ad10b943bc10690358cf2db32ca06c3e81a0 + +# Configure the build for 32-bit, static, and without test (to speed up compilation). +make clean +CC=gcc CXX=g++ CFLAGS="-m32 -Og -g3 -fno-inline-functions -fdump-rtl-expand -fsanitize=address -static-libasan" ./Configure -m32 linux-generic32 no-tests --debug +# Compile the project. +CC=gcc CXX=g++ CFLAGS="-m32 -Og -g3 -fno-inline-functions -fdump-rtl-expand -fsanitize=address -static-libasan" make \ No newline at end of file diff --git a/cve/openssl/2022/CVE-2022-3786/confirm-vulnerability.c b/cve/openssl/2022/CVE-2022-3786/confirm-vulnerability.c new file mode 100644 index 0000000000000000000000000000000000000000..e6e5b5a8334339d95e88ace99590bda576b5567b --- /dev/null +++ b/cve/openssl/2022/CVE-2022-3786/confirm-vulnerability.c @@ -0,0 +1,85 @@ +/* This file is adapted from the OpenSSL test created after the CVE. See: +** https://github.com/openssl/openssl/commit/a0af4a3c8b18c435a5a4afb28b3ad1a2730e6ea8#diff-83399d92c96bb1f4616b5c6f090053b95834cdbc7bb37bb0d835d1555f69e8ad +*/ + +#include +#include +#include +#include +#include +#include + +/* From punycode test. See link above */ +#include +#include +#include "crypto/punycode.h" +#include "internal/nelem.h" + +#define TEST_mem_eq(a, m, b, n) test_mem_eq(__FILE__, __LINE__, #a, #b, a, m, b, n) +#define TEST_false(a) test_false(__FILE__, __LINE__, #a, (a) != 0) + +int test_mem_eq(const char *file, int line, const char *st1, const char *st2, + const void *s1, size_t n1, const void *s2, size_t n2) +{ + if (s1 == NULL && s2 == NULL) + return 1; + if (n1 != n2 || s1 == NULL || s2 == NULL || memcmp(s1, s2, n1) != 0) { + return 0; + } + return 1; +} +int test_false(const char *file, int line, const char *s, int b) +{ + if (!b) + return 1; + return 0; +} + +static int test_puny_overrun(void) +{ + static const unsigned int out[] = { + 0x0033, 0x5E74, 0x0042, 0x7D44, 0x91D1, 0x516B, 0x5148, 0x751F + }; + static const char *in = "3B-ww4c5e180e575a65lsy2b"; + unsigned int buf[OSSL_NELEM(out)]; + unsigned int bsize = OSSL_NELEM(buf) - 1; + + if (!TEST_false(ossl_punycode_decode(in, strlen(in), buf, &bsize))) { + if (TEST_mem_eq(buf, bsize * sizeof(*buf), out, sizeof(out))) + puts("CRITICAL: buffer overrun detected!"); + return 0; + } + return 1; +} + +static int test_puny_overrun_crash(void) +{ + char* in = "3B-ww4c5e180e575a65lsy2b"; + unsigned int out[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Only 7-bytes now! + }; + + unsigned int bsize = OSSL_NELEM(out); // The actual size of our buffer + + int result = ossl_punycode_decode(in, strlen(in), out, &bsize); + + return 1; +} + +#define A2ULABEL_SIZE 512 +static int test_puny_overrun_large(void) +{ + unsigned int outlen = A2ULABEL_SIZE; + // Should produce 513 sized output.... + static const char* in = "3B-ww4c5e180e575a65lsy2b3B-ww4c5e180e575a65lsy2b3B-ww4c5e180e575a65lsy2b3B-ww4c5e180e575a65lsy2b3B-ww4c5e180e575a65lsy2b3B-ww4c5e180e575a65lsy2b3B-ww4c5e180e575a65lsy2b3B-ww4c5e180e575a65lsy2b3B-ww4c5e180e575a65lsy2b3B-ww4c5e180e575a65lsy2b3B-ww4c5e180e575a65lsy2b3B-ww4c5e180e575a65lsy2b3B-ww4c5e180e575a65lsy2b3B-ww4c5e180e575a65lsy2b3B-ww4c5e180e575a65lsy2b3B-ww4c5e180e575a65lsy2b3B-ww4c5e180e575a65lsy2b3B-ww4c5e180e575a65lsy2b3B-ww4c5e180e575a65lsy2b3B-ww4c5e180e575a65lsy2b3B-ww4c5e180e575a65lsy2b3B-ww4c5e180e575a65lsy2ba"; + unsigned int out[A2ULABEL_SIZE]; + memset(out, 0xdd, sizeof(out)); + + int result = ossl_punycode_decode(in, strlen(in), out, &outlen); + + return 1; +} + +int main(int argc, char ** argv) { + return test_puny_overrun_large(); +} \ No newline at end of file diff --git a/cve/openssl/2022/CVE-2022-3786/harness.c b/cve/openssl/2022/CVE-2022-3786/harness.c new file mode 100644 index 0000000000000000000000000000000000000000..dbcb3dd7dd51faf98828bdf921006b4924f45dba --- /dev/null +++ b/cve/openssl/2022/CVE-2022-3786/harness.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include + +/* From punycode test. See link below. +** https://github.com/openssl/openssl/commit/a0af4a3c8b18c435a5a4afb28b3ad1a2730e6ea8#diff-83399d92c96bb1f4616b5c6f090053b95834cdbc7bb37bb0d835d1555f69e8ad +*/ +#include +#include + +#include "crypto/punycode.h" +#include "internal/nelem.h" + +/* This is from crypto/punycode.c +** Why not the header? I dunno. */ +#define LABEL_BUF_SIZE 512 + +int main(int argc, char ** argv){ + + int fd; + struct stat stat; + int result; + + /* Ensure we have the correct number of arguments. */ + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + /* Open the file passed in to argv[1]. */ + fd = open(argv[1], O_RDONLY); + /* Check that the file exists. */ + if (fd < 0) { + perror("Open"); + return EXIT_FAILURE; + } + + /* Get the size of the file. */ + if (fstat(fd, &stat) < 0) { + perror("fstat"); + return EXIT_FAILURE; + } + + /* Create a buffer of that size. */ + char * in = malloc(stat.st_size); + + /* Read the contents of the file into the buffer at once. */ + if (read(fd, in, stat.st_size) < 0) { + perror("read"); + return EXIT_FAILURE; + } + + /* If DEBUG is defined, print the contents of the buffer. + ** Users can set this at compilation time with -DDEBUG + */ + #ifdef DEBUG + printf("The contents of the file: %s", in); + #endif + + /* Call the function we want to test. */ + char ulabel[256]; + size_t size = sizeof(ulabel) - 1; + memset(ulabel, 0, sizeof(ulabel)); + result = ossl_a2ulabel(in, ulabel, &size); + printf("ossl_a2ulabel returned: %d\n", result); + + /* Free the buffer and set it to NULL. */ + free(in); + in = NULL; + + /* Exit the program. */ + return result; +} diff --git a/cve/openssl/2022/CVE-2022-3786/run.sh b/cve/openssl/2022/CVE-2022-3786/run.sh new file mode 100644 index 0000000000000000000000000000000000000000..b92b5b5a915fd0e9c7ad3dd167168631ce4800d3 --- /dev/null +++ b/cve/openssl/2022/CVE-2022-3786/run.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +# Change the title of the gnome-shell. +printf "\e]2;openssl\a" +# I don't have a dedicated fuzzing machine, limit the CPU scaler. +export AFL_AUTORESUME=1 +export AFL_SKIP_CPUFREQ=1 +afl-fuzz -i /input -o /output /harness/harness @@ diff --git a/cve/openssl/2022/yaml/CVE-2022-3786.yaml b/cve/openssl/2022/yaml/CVE-2022-3786.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c532b8a2628b67b938cc5453165e60bb4e5ca9ef --- /dev/null +++ b/cve/openssl/2022/yaml/CVE-2022-3786.yaml @@ -0,0 +1,19 @@ +id: CVE-2022-3786 +source: https://github.com/WhatTheFuzz/openssl-fuzz +info: + name: 在TLS客户端中,通过连接到恶意服务器来触发漏洞。如果服务器请求客户端身份验证而恶意客户端连接,触发OpenSSL缓冲区溢出漏洞。 + severity: High + description: | + 在X.509证书验证中,特别是在名称约束检查中,可能会触发缓冲区溢出。这种情况发生在证书链签名验证之后,并且要求CA已经签署了恶意证书,或者要求应用程序在无法构造到受信任的颁发者的路径的情况下继续进行证书验证。攻击者可以在证书中伪造一个恶意的电子邮件地址来溢出任意数量的字节,其中包含'。'字符(十进制46)。缓冲区溢出可能导致崩溃(导致拒绝服务)。 + scope-of-influence: + 3.0.0 <= OpenSSL <= 3.0.6 + reference: + https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=c42165b5706e42f67ef8ef4c351a9a4c5d21639a + classification: + cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H + cvss-score: 7.5 + cve-id: CVE-2022-3786 + cwe-id: CWE-120 + cnvd-id: None + kve-id: None + tags: 缓冲区溢出, CVE-2022 \ No newline at end of file diff --git a/openkylin_list.yaml b/openkylin_list.yaml index 9280183190cb5781088a8c0d53c20d5363f5016d..0ae500846f048d309ee6e0bd69b9116213fc066e 100644 --- a/openkylin_list.yaml +++ b/openkylin_list.yaml @@ -71,6 +71,7 @@ cve: - CVE-2023-25136 - CVE-2021-3449 - CVE-2022-0778 + - CVE-2022-3786 libxml2: - CVE-2020-24977 - CVE-2021-3517