A remote code execution vulnerability has been reported in GoAhead versions 2.x and 3.x in the CGI handler on Linux. This impacts those sites that use dynamically linked CGI programs with GoAhead on Linux.
The GoAhead CGI handler accepts HTTP query and form data parameters and creates CGI environment variables for each parameter. On Linux, if a parameter of the name LD_PRELOAD is supplied and set to the standard input, the POST data may be accepted as code and may be pre-loaded into dynamically linked CGI processes before they run. This permits arbitrary code injection into the CGI process on Linux.
To exploit the vulnerability, an attacker would create an HTTP CGI request that uses sets LD_PRELOAD=/proc/self/fd/0 in the query string and sets the POST data of the request to be in the form of a malicious shared library for the architecture of the device.
Upgrade to GoAhead 3.6.5 if you are using dynamically linked CGI programs on Linux.
The fix applied in GoAhead 3.6.5 filters all CGI variables that begin LD_ and IFS.
As part of a more general and robust solution a new main.me property “cgiVarPrefix” is added. When set to “CGI_” (the default), all user supplied query and form variables are prefixed with CGI_. This will require changes to your CGI programs to expect this prefix. It is recommended that users do this.
Alternatively, if CGI programs cannot be updated, set the cgiVarPrefix to the empty string. The filtering of LD_ and IFS variables should suffice, but it is strongly recommended that you set cgiVarPrefix to a non-empty string at the earliest opportunity.
If you have a current GoAhead maintenance agreement, you are covered and can apply the update. If you do not have maintenance, please contact Embedthis at sales@embedthis.com to reinstate GoAhead maintenance so you can apply the patch.
diff --git a/src/cgi.c b/src/cgi.c
index 899ec97..18d9b45 100644
--- a/src/cgi.c
+++ b/src/cgi.c
@@ -160,10 +160,17 @@ PUBLIC bool cgiHandler(Webs *wp)
envpsize = 64;
envp = walloc(envpsize * sizeof(char*));
for (n = 0, s = hashFirst(wp->vars); s != NULL; s = hashNext(wp->vars, s)) {
- if (s->content.valid && s->content.type == string &&
- strcmp(s->name.value.string, "REMOTE_HOST") != 0 &&
- strcmp(s->name.value.string, "HTTP_AUTHORIZATION") != 0) {
- envp[n++] = sfmt("%s=%s", s->name.value.string, s->content.value.string);
+ if (s->content.valid && s->content.type == string) {
+ if (smatch(s->name.value.string, "REMOTE_HOST") ||
+ smatch(s->name.value.string, "HTTP_AUTHORIZATION") ||
+ smatch(s->name.value.string, "IFS") ||
+ smatch(s->name.value.string, "CDPATH") ||
+ smatch(s->name.value.string, "PATH") ||
+ sstarts(s->name.value.string, "LD_")) {
+ continue;
+ }
{{comment.name}} said ...
{{comment.message}}