Internet Bug Bounty · Report #850775
Windows only: arbitrary file read vulnerability in openssl s_server
How it was found
==(Copied from an email sent to [email protected] on August 15, 2019)==
Hi,
There's an arbitrary file read vulnerability present in openssl s_server when ran on Windows with the -WWW or -HTTP option. To reproduce:
- run
openssl s_server -tls1 -WWW -accept 443 - run
.\curl.exe -k https://127.0.0.1/..\..\..\..\..\..\..\any-file - observe the contents of any-file, which could be located outside of the running directory, to be returned to the user
The root cause of this vulnerability seems to come from an incomplete check in path parsing logic: https://github.com/openssl/openssl/blob/master/apps/s_server.c#L3225. Ideally, it'd include a check for a backslash, too. It seems that this particular code has been around for some time.
Vulnerable versions seem to include 0.9.6, 0.9.7, 0.9.8, 1.0.0, 1.0.1, 1.0.2, 1.1.0, and 1.1.1.
This was tested against OpenSSL 1.1.1c on Windows 10 (64-bit).
The maintainers fixed this in this commit:
diff --git a/apps/s_server.c b/apps/s_server.c
index 038046808037..5f58ef68fefa 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -3211,6 +3211,12 @@ static int www_body(int s, int stype, int prot, unsigned char *context)
if (e[0] == ' ')
break;
+ if (e[0] == ':') {
+ /* Windows drive. We treat this the same way as ".." */
+ dot = -1;
+ break;
+ }
+
switch (dot) {
case 1:
dot = (e[0] == '.') ? 2 : 0;
@@ -3219,11 +3225,11 @@ static int www_body(int s, int stype, int prot, unsigned char *context)
dot = (e[0] == '.') ? 3 : 0;
break;
case 3:
- dot = (e[0] == '/') ? -1 : 0;
+ dot = (e[0] == '/' || e[0] == '\\') ? -1 : 0;
break;
}
if (dot == 0)
- dot = (e[0] == '/') ? 1 : 0;
+ dot = (e[0] == '/' || e[0] == '\\') ? 1 : 0;
}
dot = (dot == 3) || (dot == -1); /* filename contains ".."
* component */
@@ -3237,11 +3243,11 @@ static int www_body(int s, int stype, int prot, unsigned char *context)
if (dot) {
BIO_puts(io, text);
- BIO_printf(io, "'%s' contains '..' reference\r\n", p);
+ BIO_printf(io, "'%s' contains '..' or ':'\r\n", p);
break;
}
- if (*p == '/') {
+ if (*p == '/' || *p == '\\') {
BIO_puts(io, text);
BIO_printf(io, "'%s' is an invalid path\r\n", p);
break;
Impact
An attacker may be able to read arbitrary files from a user's file system.