Source code pulled from OpenBSD for LibreSSL - this includes most of the library and supporting code. The place to contribute to this code is via the OpenBSD CVS tree. Please mail patches to tech@openbsd.org, instead of submitting pull requests, since this tree is often rebased.
230
stars
92
forks
source link
stack-buffer-overflow(max 5byte) in print_bin() when indent is specified as 124 or more #145
First of all, this is a stack buffer overflow, but it is quite difficult to exploit because the fixed value ' ' (0x20) is written up to 5 bytes.
Also, since it is necessary to specify 124 or more for indent, the range of influence is small.
I simply found it by chance, so I'd like to report it.
(Coverity discovered this by chance when I added a variable to print_bin() locally)
The symptom is that when calling ECPKParameters_print() with an explicit curve ecparam which has seed and with indent 124 or higher, a stack-buffer-overflow of up to 5 bytes occurs.
The same symptoms also occur with APIs that internally call ECPKParameters_print(), such as EVP_PKEY_print_params().
The cause is in print_bin of eck_prn.c.
In line 342, the memset of size off+4 is performed from the position of str[1], so the variable off must be less than sizeof(str) - 4 -1, that is, less than 123.
However, line 330 checks that off is less than or equal to 128 (=sizeof(str)).
Therefore, if a value of 124 or more is specified for the argument off, a stack buffer overflow of up to 5 bytes will occur.
https://github.com/libressl/openbsd/blob/17c60e5b8955deb5786d3f1577b5532478186585/src/lib/libcrypto/ec/eck_prn.c#L325-L342
It seems that the value to be checked needs to be appropriate.
For example, as below.
diff --git a/src/lib/libcrypto/ec/eck_prn.c b/src/lib/libcrypto/ec/eck_prn.c
index 6e89bfa73..cdf19eb8f 100644
--- a/src/lib/libcrypto/ec/eck_prn.c
+++ b/src/lib/libcrypto/ec/eck_prn.c
@@ -327,8 +327,8 @@ print_bin(BIO *fp, const char *name, const unsigned char *buf,
if (buf == NULL)
return 1;
if (off) {
- if (off > 128)
- off = 128;
+ if (off > sizeof(str) - 4 - 1)
+ off = sizeof(str) - 4 - 1;
memset(str, ' ', off);
if (BIO_write(fp, str, off) <= 0)
return 0;
The quickest way to create parameters is to specify explicit flag with a named curve as shown below.
Please note that you need to choose a curve that has a seed parameter.
$ openssl ecparam -param_enc explicit -name secp384r1 -genkey -out explicit.key -outform PEM
If you pass the parameters created in this way to ECPKParameters_print() with an indent of 124 or higher, it will be reproduced.
The reproduction program is as follows.
main.c
#include <stdio.h>
#include <openssl/bio.h>
#include <openssl/ec.h>
#include <openssl/pem.h>
#include <stdio.h>
#include <openssl/bio.h>
#include <openssl/ec.h>
#include <openssl/pem.h>
// created with "openssl ecparam -param_enc explicit -name secp384r1 -outform PEM"
// Need to choose a curve which has a seed
static char *ecparam_pem=
"-----BEGIN EC PARAMETERS-----\n"
"MIIBVwIBATA8BgcqhkjOPQEBAjEA////////////////////////////////////\n"
"//////7/////AAAAAAAAAAD/////MHsEMP//////////////////////////////\n"
"///////////+/////wAAAAAAAAAA/////AQwszEvp+I+5+SYjgVr4/gtGRgdnG7+\n"
"gUESAxQIj1ATh1rGVjmNii7RnSqFyO3T7CrvAxUAozWSaqMZonodAIlqZ3OkgnrN\n"
"rHMEYQSqh8oivosFN46xxx7zIK10bh07Younm5hZ90HgglQqOFUC8l2/VSlsOlRe\n"
"OHJ2Crc2F95KliYsb12emL+Sktwp+PQdvSiaFHzp2jETtfC4wApgsc4dfoGdekMd\n"
"fJDqDl8CMQD////////////////////////////////HY02B9Dct31gaDbJIsKd6\n"
"7OwZaszFKXMCAQE=\n"
"-----END EC PARAMETERS-----\n";
#define INDENT 124
int main(int argc, char**argv)
{
BIO *mem = NULL, *out = NULL;
EC_GROUP *group = NULL;
// for ECPKParameters_print's output
out = BIO_new(BIO_s_file());
if (out == NULL)
goto err;
BIO_set_fp(out, stdout, BIO_NOCLOSE);
// load pem to bio
mem = BIO_new_mem_buf(ecparam_pem, -1);
if (mem == NULL)
goto err;
// create group from bio
group = PEM_read_bio_ECPKParameters(mem, NULL, NULL, NULL);
if (group == NULL)
goto err;
// if INDENT >= 124, stack buffer overflow(max 5byte) occur in print_bin()
ECPKParameters_print(out, group, INDENT);
err:
BIO_free(mem);
BIO_free_all(out);
EC_GROUP_free(group);
}
I statically linked libressl's libcrypto.a and executed it with the following command.
$ gcc main.c crypto/.libs/libcrypto.a -lpthread
$ ./a.out
backtrace
$ ./a.out
Field Type: prime-field
Prime:
00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:
ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:
ff:ff:fe:ff:ff:ff:ff:00:00:00:00:00:00:00:00:
ff:ff:ff:ff
A:
00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:
ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:
ff:ff:fe:ff:ff:ff:ff:00:00:00:00:00:00:00:00:
ff:ff:ff:fc
B:
00:b3:31:2f:a7:e2:3e:e7:e4:98:8e:05:6b:e3:f8:
2d:19:18:1d:9c:6e:fe:81:41:12:03:14:08:8f:50:
13:87:5a:c6:56:39:8d:8a:2e:d1:9d:2a:85:c8:ed:
d3:ec:2a:ef
Generator (uncompressed):
04:aa:87:ca:22:be:8b:05:37:8e:b1:c7:1e:f3:20:
ad:74:6e:1d:3b:62:8b:a7:9b:98:59:f7:41:e0:82:
54:2a:38:55:02:f2:5d:bf:55:29:6c:3a:54:5e:38:
72:76:0a:b7:36:17:de:4a:96:26:2c:6f:5d:9e:98:
bf:92:92:dc:29:f8:f4:1d:bd:28:9a:14:7c:e9:da:
31:13:b5:f0:b8:c0:0a:60:b1:ce:1d:7e:81:9d:7a:
43:1d:7c:90:ea:0e:5f
Order:
00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:
ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:c7:63:4d:81:f4:
37:2d:df:58:1a:0d:b2:48:b0:a7:7a:ec:ec:19:6a:
cc:c5:29:73
Cofactor: 1 (0x1)
*** buffer overflow detected ***: ./a.out terminated
Aborted (core dumped)
...
(gdb) bt
#0 0x00007f5a32794acf in raise () from /lib64/libc.so.6
#1 0x00007f5a32767ea5 in abort () from /lib64/libc.so.6
#2 0x00007f5a327d5cd7 in __libc_message () from /lib64/libc.so.6
#3 0x00007f5a328849c5 in __fortify_fail_abort () from /lib64/libc.so.6
#4 0x00007f5a328849f7 in __fortify_fail () from /lib64/libc.so.6
#5 0x00007f5a32882a96 in __chk_fail () from /lib64/libc.so.6
#6 0x00000000004063aa in memset (__len=128, __ch=32, __dest=0x7ffe5409ca71)
at /usr/include/bits/string_fortified.h:74
#7 print_bin (name=0x4c80b1 "Seed:", off=124, len=20,
buf=0x1449710 "\243\065\222j\243\031\242z\035", fp=0x14372a0) at ec/eck_prn.c:342
#8 ecpk_print_explicit_parameters (off=124, group=<optimized out>, bp=0x14372a0)
at ec/eck_prn.c:293
#9 ECPKParameters_print (bp=0x14372a0, group=<optimized out>, off=<optimized out>)
at ec/eck_prn.c:316
#10 0x0000000000401e82 in main ()
LibreSSL version
This issue is reproducible on LibreSSL master.
OS
RockyLinux8
(In addition, there is just one more bug, so I will write another issue immediately after this.)
First of all, this is a stack buffer overflow, but it is quite difficult to exploit because the fixed value ' ' (0x20) is written up to 5 bytes. Also, since it is necessary to specify 124 or more for indent, the range of influence is small. I simply found it by chance, so I'd like to report it. (Coverity discovered this by chance when I added a variable to print_bin() locally)
The symptom is that when calling ECPKParameters_print() with an explicit curve ecparam which has seed and with indent 124 or higher, a stack-buffer-overflow of up to 5 bytes occurs.
The same symptoms also occur with APIs that internally call ECPKParameters_print(), such as EVP_PKEY_print_params().
The cause is in print_bin of eck_prn.c. In line 342, the memset of size off+4 is performed from the position of str[1], so the variable off must be less than sizeof(str) - 4 -1, that is, less than 123. However, line 330 checks that off is less than or equal to 128 (=sizeof(str)). Therefore, if a value of 124 or more is specified for the argument off, a stack buffer overflow of up to 5 bytes will occur. https://github.com/libressl/openbsd/blob/17c60e5b8955deb5786d3f1577b5532478186585/src/lib/libcrypto/ec/eck_prn.c#L325-L342
It seems that the value to be checked needs to be appropriate. For example, as below.
print_bin is called when displaying the seed in ecpk_print_explicit_parameters(). Therefore, the influence is limited to when the parameter has a seed. https://github.com/libressl/openbsd/blob/17c60e5b8955deb5786d3f1577b5532478186585/src/lib/libcrypto/ec/eck_prn.c#L293
ecpk_print_explicit_parameters() is called when ECPKParameters_print() passes an EC_GROUP without asn1_flag set. And asn1_flag is 0 when it is an explicit curve. Therefore, the effect is limited to explicit curves only. https://github.com/libressl/openbsd/blob/17c60e5b8955deb5786d3f1577b5532478186585/src/lib/libcrypto/ec/eck_prn.c#L313-L316
How to reproduce
The quickest way to create parameters is to specify explicit flag with a named curve as shown below. Please note that you need to choose a curve that has a seed parameter. $ openssl ecparam -param_enc explicit -name secp384r1 -genkey -out explicit.key -outform PEM
If you pass the parameters created in this way to ECPKParameters_print() with an indent of 124 or higher, it will be reproduced. The reproduction program is as follows.
main.c
I statically linked libressl's libcrypto.a and executed it with the following command. $ gcc main.c crypto/.libs/libcrypto.a -lpthread $ ./a.out
backtrace
LibreSSL version
This issue is reproducible on LibreSSL master.
OS
RockyLinux8
(In addition, there is just one more bug, so I will write another issue immediately after this.)