Skip to content
This repository was archived by the owner on Apr 23, 2020. It is now read-only.

Commit b035d53

Browse files
committed
[libFuzzer] add a fuzzer test that finds CVE-2015-3193
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@282892 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 976632d commit b035d53

File tree

3 files changed

+184
-0
lines changed

3 files changed

+184
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/bin/bash
2+
3+
[ -e $(basename $0) ] && echo "PLEASE USE THIS SCRIPT FROM ANOTHER DIR" && exit 1
4+
SCRIPT_DIR=$(dirname $0)
5+
EXECUTABLE_NAME_BASE=$(basename $SCRIPT_DIR)
6+
LIBFUZZER_SRC=$(dirname $(dirname $SCRIPT_DIR))
7+
JOBS=20
8+
9+
# FUZZ_CXXFLAGS=" -g -fsanitize=address -fsanitize-coverage=edge"
10+
FUZZ_CXXFLAGS=" -g -fsanitize=address -fsanitize-coverage=trace-pc-guard,trace-cmp,trace-div,trace-gep"
11+
12+
get() {
13+
[ ! -e SRC ] && git clone https://github.com/openssl/openssl.git SRC && (cd SRC && git checkout OpenSSL_1_0_2d)
14+
# [ ! -e SRC ] && wget https://www.openssl.org/source/openssl-1.0.1f.tar.gz && tar xf openssl-1.0.1f.tar.gz && mv openssl-1.0.1f SRC
15+
}
16+
build_lib() {
17+
rm -rf BUILD
18+
cp -rf SRC BUILD
19+
(cd BUILD && ./config && make clean && make CC="clang $FUZZ_CXXFLAGS" -j $JOBS)
20+
}
21+
22+
get
23+
build_lib
24+
$LIBFUZZER_SRC/build.sh
25+
echo clang++ -g $SCRIPT_DIR/target.cc -DCERT_PATH=\"$SCRIPT_DIR/\" $FUZZ_CXXFLAGS BUILD/libssl.a BUILD/libcrypto.a libFuzzer.a -lgcrypt -o $EXECUTABLE_NAME_BASE
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
// Find CVE-2015-3193. Derived from
2+
// https://github.com/hannob/bignum-fuzz/blob/master/CVE-2015-3193-openssl-vs-gcrypt-modexp.c
3+
/* Fuzz-compare the OpenSSL function BN_mod_exp() and the libgcrypt function gcry_mpi_powm().
4+
*
5+
* To use this you should compile both libgcrypt and openssl with american fuzzy lop and then statically link everything together, e.g.:
6+
* afl-clang-fast -o [output] [input] libgcrypt.a libcrypto.a -lgpg-error
7+
*
8+
* Input is a binary file, the first bytes will decide how the rest of the file will be split into three bignums.
9+
*
10+
* by Hanno Böck, license CC0 (public domain)
11+
*/
12+
13+
#include <stdio.h>
14+
#include <stdlib.h>
15+
#include <string.h>
16+
#include <assert.h>
17+
#include <openssl/bn.h>
18+
#include <gcrypt.h>
19+
20+
#define MAXBUF 1000000
21+
22+
23+
struct big_results {
24+
char *name;
25+
char *a;
26+
char *b;
27+
char *c;
28+
char *exptmod;
29+
};
30+
31+
void printres(struct big_results *res) {
32+
printf("\n%s:\n", res->name);
33+
printf("a: %s\n", res->a);
34+
printf("b: %s\n", res->b);
35+
printf("c: %s\n", res->c);
36+
printf("b^c mod a: %s\n", res->exptmod);
37+
}
38+
39+
void freeres(struct big_results *res) {
40+
free(res->a);
41+
free(res->b);
42+
free(res->c);
43+
free(res->exptmod);
44+
}
45+
46+
47+
char *gcrytostring(gcry_mpi_t in) {
48+
char *a, *b;
49+
size_t i;
50+
size_t j=0;
51+
gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char**) &a, &i, in);
52+
while(a[j]=='0' && j<(i-2)) j++;
53+
if ((j%2)==1) j--;
54+
if (strncmp(&a[j],"00",2)==0) j++;
55+
b=(char*)malloc(i-j);
56+
strcpy(b, &a[j]);
57+
free(a);
58+
return b;
59+
}
60+
61+
/* test gcry functions from libgcrypt */
62+
void gcrytest(unsigned char* a_raw, int a_len, unsigned char* b_raw, int b_len, unsigned char* c_raw, int c_len, struct big_results *res) {
63+
gcry_mpi_t a, b, c, res1, res2;
64+
65+
/* unknown leak here */
66+
gcry_mpi_scan(&a, GCRYMPI_FMT_USG, a_raw, a_len, NULL);
67+
res->a = gcrytostring(a);
68+
69+
gcry_mpi_scan(&b, GCRYMPI_FMT_USG, b_raw, b_len, NULL);
70+
res->b = gcrytostring(b);
71+
72+
gcry_mpi_scan(&c, GCRYMPI_FMT_USG, c_raw, c_len, NULL);
73+
res->c = gcrytostring(c);
74+
75+
res1=gcry_mpi_new(0);
76+
77+
gcry_mpi_powm(res1, b, c, a);
78+
res->exptmod=gcrytostring(res1);
79+
80+
gcry_mpi_release(a);
81+
gcry_mpi_release(b);
82+
gcry_mpi_release(c);
83+
gcry_mpi_release(res1);
84+
}
85+
86+
/* test bn functions from openssl/libcrypto */
87+
void bntest(unsigned char* a_raw, int a_len, unsigned char* b_raw, int b_len, unsigned char* c_raw, int c_len, struct big_results *res) {
88+
BN_CTX *bctx = BN_CTX_new();
89+
BIGNUM *a = BN_new();
90+
BIGNUM *b = BN_new();
91+
BIGNUM *c = BN_new();
92+
BIGNUM *res1 = BN_new();
93+
94+
BN_bin2bn(a_raw, a_len, a);
95+
BN_bin2bn(b_raw, b_len, b);
96+
BN_bin2bn(c_raw, c_len, c);
97+
98+
res->a = BN_bn2hex(a);
99+
res->b = BN_bn2hex(b);
100+
res->c = BN_bn2hex(c);
101+
102+
BN_mod_exp(res1, b, c, a, bctx);
103+
res->exptmod = BN_bn2hex(res1);
104+
105+
BN_free(a);
106+
BN_free(b);
107+
BN_free(c);
108+
BN_free(res1);
109+
BN_CTX_free(bctx);
110+
}
111+
112+
extern "C" int LLVMFuzzerTestOneInput(const unsigned char *Data, size_t Size) {
113+
size_t len, l1, l2,l3;
114+
unsigned int divi1, divi2;
115+
unsigned char *a, *b, *c;
116+
struct big_results openssl_results= {"openssl",0,0,0,0};
117+
struct big_results gcrypt_results= {"libgcrypt",0,0,0,0};
118+
119+
len = Size;
120+
if (len<5) return 0;
121+
122+
divi1=Data[0];
123+
divi2=Data[1];
124+
divi1++;divi2++;
125+
l1 = (len-2)*divi1/256;
126+
l2 = (len-2-l1)*divi2/256;
127+
l3 = (len-2-l1-l2);
128+
assert(l1+l2+l3==len-2);
129+
//printf("div1 div2 %i %i\n", divi1, divi2);
130+
//printf("len l1 l2 l3 %i %i %i %i\n", (int)len,(int)l1,(int)l2,(int)l3);
131+
a=const_cast<unsigned char*>(Data)+2;
132+
b=const_cast<unsigned char*>(Data)+2+l1;
133+
c=const_cast<unsigned char*>(Data)+2+l1+l2;
134+
135+
136+
bntest(a, l1, b, l2, c, l3, &openssl_results);
137+
//printres(&openssl_results);
138+
if ((strcmp(openssl_results.a,"0")==0) || (strcmp(openssl_results.c,"0")==0)) goto END;
139+
140+
gcrytest(a, l1, b, l2, c, l3, &gcrypt_results);
141+
//printres(&gcrypt_results);
142+
143+
assert(strcmp(openssl_results.exptmod, gcrypt_results.exptmod)==0);
144+
145+
END:
146+
freeres(&openssl_results);
147+
freeres(&gcrypt_results);
148+
return 0;
149+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/bash
2+
set -x
3+
SCRIPT_DIR=$(dirname $0)
4+
EXECUTABLE_NAME_BASE=$(basename $SCRIPT_DIR)
5+
CORPUS=CORPUS-$EXECUTABLE_NAME_BASE
6+
JOBS=8
7+
rm -rf $CORPUS
8+
mkdir $CORPUS
9+
[ -e $EXECUTABLE_NAME_BASE ] && ./$EXECUTABLE_NAME_BASE -artifact_prefix=$CORPUS/ -max_len=512 -jobs=$JOBS -workers=$JOBS $CORPUS
10+
grep 'Assertion `strcmp(openssl_results.exptmod, gcrypt_results.exptmod)==0. failed.' fuzz-0.log

0 commit comments

Comments
 (0)