CVE-2016-6255: Improper Access Control (CWE-284)
value: Portable UPnP SDK (aka libupnp) before 1.6.21 allows remote attackers to write to arbitrary files in the webroot via a POST request without a registered handler.
CWE description: The product does not restrict or incorrectly restricts access to a resource from an unauthorized actor.
CVSS v3 base score: 7.5
Published: 2017-03-07T16:59Z
Repository: https://github.com/mjg59/pupnp-code
Language: Other
Files changed: configure.ac, upnp/inc/upnpconfig.h.in, upnp/src/genlib/net/http/webserver.c
Commit date: 2016-07-18 08:59:09 -0700
Commit message: Don't allow unhandled POSTs to write to the filesystem by default

If there's no registered handler for a POST request, the default behaviour
is to write it to the filesystem. Several million deployed devices appear
to have this behaviour, making it possible to (at least) store arbitrary
data on them. Add a configure option that enables this behaviour, and change
the default to just drop POSTs that aren't directly handled.

Diff: diff --git a/configure.ac b/configure.ac
index dd88734..ea2bc09 100644
--- a/configure.ac
+++ b/configure.ac
@@ -480,10 +480,14 @@ fi
 RT_BOOL_ARG_ENABLE([scriptsupport], [yes], [script support for IXML document tree, see ixml.h])
 if test "x$enable_scriptsupport" = xyes ; then
         AC_DEFINE(IXML_HAVE_SCRIPTSUPPORT, 1, [see upnpconfig.h])
 fi
 
+RT_BOOL_ARG_ENABLE([postwrite], [no], [write to the filesystem on otherwise unhandled POST requests])
+if test "x$enable_postwrite" = xyes ; then
+        AC_DEFINE(UPNP_ENABLE_POST_WRITE, 1, [see upnpconfig.h])
+fi
 
 RT_BOOL_ARG_ENABLE([samples], [yes], [compilation of upnp/sample/ code])
 
 
 #
diff --git a/upnp/inc/upnpconfig.h.in b/upnp/inc/upnpconfig.h.in
index 46ddc6e..5df8c5a 100644
--- a/upnp/inc/upnpconfig.h.in
+++ b/upnp/inc/upnpconfig.h.in
@@ -133,7 +133,12 @@
 
 /** Defined to 1 if the library has been compiled with OpenSSL support
  *  (i.e. configure --enable-open_ssl) */
 #undef UPNP_ENABLE_OPEN_SSL
 
+/** Defined to 1 if the library has been compiled to support filesystem writes on POST
+ *  (i.e. configure --enable-postwrite) */
+#undef UPNP_ENABLE_POST_WRITE
+
+
 #endif /* UPNP_CONFIG_H */
 
diff --git a/upnp/src/genlib/net/http/webserver.c b/upnp/src/genlib/net/http/webserver.c
index 8991c16..8b2ecf2 100644
--- a/upnp/src/genlib/net/http/webserver.c
+++ b/upnp/src/genlib/net/http/webserver.c
@@ -1367,13 +1367,17 @@ static int http_RecvPostMessage(
 	if (Instr && Instr->IsVirtualFile) {
 		Fp = (virtualDirCallback.open) (filename, UPNP_WRITE);
 		if (Fp == NULL)
 			return HTTP_INTERNAL_SERVER_ERROR;
 	} else {
+#ifdef UPNP_ENABLE_POST_WRITE
 		Fp = fopen(filename, "wb");
 		if (Fp == NULL)
 			return HTTP_UNAUTHORIZED;
+#else
+		return HTTP_NOT_FOUND;
+#endif
 	}
 	parser->position = POS_ENTITY;
 	do {
 		/* first parse what has already been gotten */
 		if (parser->position != POS_COMPLETE)

Fixed code: RT_BOOL_ARG_ENABLE([postwrite], [no], [write to the filesystem on otherwise unhandled POST requests])
if test "x$enable_postwrite" = xyes ; then
        AC_DEFINE(UPNP_ENABLE_POST_WRITE, 1, [see upnpconfig.h])
fi
/** Defined to 1 if the library has been compiled to support filesystem writes on POST
 *  (i.e. configure --enable-postwrite) */
#undef UPNP_ENABLE_POST_WRITE


#ifdef UPNP_ENABLE_POST_WRITE
#else
		return HTTP_NOT_FOUND;
#endif