Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PATH_INFO incorrectly set with multipart/form-data POST with files #2198

Closed
perillo opened this issue Apr 24, 2019 · 11 comments
Closed

PATH_INFO incorrectly set with multipart/form-data POST with files #2198

perillo opened this issue Apr 24, 2019 · 11 comments

Comments

@perillo
Copy link

perillo commented Apr 24, 2019

I'm having the same issue as reported at:
https://stackoverflow.com/questions/49594955/django-1-11-on-passenger-wsgi-not-routing-post-request?rq=1.

However in my case PATH_INFO is incorrectly set only with multipart/form-data POST and only when uploading a file.

I'm using Passenger 5.3.7 with Apache on a shared hosting:
Apache/2.4.39 (cPanel) OpenSSL/1.0.2r mod_bwlimited/1.4 Phusion_Passenger/5.3.7

@CamJN
Copy link
Contributor

CamJN commented Apr 24, 2019

Can you provide a test case please?

@perillo
Copy link
Author

perillo commented Apr 25, 2019

Here is a live example that reproduces the issue.

https://fast-page.it/passenger-issue-2198/a/b/c/

The output for a GET request is

REQUEST_METHOD: GET
SCRIPT_NAME: 
PATH_INFO: /passenger-issue-2198/a/b/c/

The output for a POST request is

REQUEST_METHOD: POST
SCRIPT_NAME: /passenger-issue-2198/a
PATH_INFO: /b/c/

Note how SCRIPT_NAME and PATH_INFO change from a GET request and a POST request.
If the file input is removed there is no change.

The .htaccess file is:

PassengerAppRoot "/home/xxx/python/passenger"
PassengerBaseURI "/passenger-issue-2198"
PassengerPython "/home/xxx/.local/share/virtualenv/passenger/bin/python"

The template.html is https://paste.ofcode.org/cLag4HygUNa7x3EdnBwxx5.
Note that expires after 1 week.

It seems that there are two issues here:

  1. For a GET request Passenger does not set SCRIPT_NAME to the value of PassengerBaseURI
  2. For a POST request with a file, Passenger shifts PATH_INFO.

Thanks.

@CamJN
Copy link
Contributor

CamJN commented Apr 29, 2019

Unfortunately I cannot reproduce the issue on my own server, so I suspect this might be a configuration issue with the host you are using.

@perillo
Copy link
Author

perillo commented Apr 29, 2019

What version are you using?

@CamJN
Copy link
Contributor

CamJN commented Apr 30, 2019

Hmm, good point. I tested using 6.0.2, I'll redo it using 5.3.7.

@CamJN
Copy link
Contributor

CamJN commented Apr 30, 2019

Yeah even uploading a pretty big file, with the app running on Passenger 5.3.7 I get the same result:

Screen Shot 2019-04-30 at 9 23 29 AM

@skokhan-x
Copy link

skokhan-x commented Jul 22, 2019

We encountered such a problem and it was caused by one of the rules of the mod_security module. Try to disable it and test the application again.

@skokhan-x
Copy link

skokhan-x commented Jul 22, 2019

@CamJN
It looks like we found the root of the issue. It consists precisely in the rule of the mod_security which uses the @inspectFile operator.

SecRule FILES_TMPNAMES "@inspectFile /etc/test.sh" \ "log,\ auditlog,\ deny,\ severity:2,\ phase:2,\ t:none,\ id:20,\ msg:'Attempt to upload malware||%{REQUEST_HEADERS.Host}',\ ctl:RuleEngine=On"

Where /etc/test.sh is:
#!/bin/bash
echo "1 OK"

Don't forget to do chmod 755 /etc/test.sh.

It seems that after the inspectFile processing is performed, the control returns incorrectly from the mod_security to the mod_passenger.

Can you try to do it on your test server?

@CamJN
Copy link
Contributor

CamJN commented Jul 22, 2019

If mod security is modifying the request data then there's not much we can do about that; unfortunately.

@skokhan-x
Copy link

skokhan-x commented Jul 29, 2019

Actually, there is a solution :)

The mod_security does not change anything in the request; it simply adds additional environment variables (such as PATH_INFO and SCRIPT_NAME) that later breaks the application.

For example, the variables with which the application will spawn when the rule described above is enabled:

[ D 2019-07-29 05:20:53.2709 956299/Te age/Cor/Spa/Han/Prepare.h:284 ]: [App spawn arg] {
   "UNIX_PATH_MAX" : 107,
   "api_key" : "MxDLMbPNwRbcjqXt",
   "app_env" : "production",
   "app_group_name" : "/home/tstdomain1/mypythonapp (production)",
   "app_root" : "/home/tstdomain1/mypythonapp",
   "app_type" : "python",
   "base_uri" : "/",
   "connect_password" : "MxDLMbPNwRbcjqXt",
   "environment_variables" : {
      "CONTENT_LENGTH" : "57035",
      "CONTENT_TYPE" : "multipart/form-data; boundary=----WebKitFormBoundarynL8BLCF9qiUVIzir",
      "CONTEXT_DOCUMENT_ROOT" : "/home/tstdomain1/public_html/wordpress",
      "CONTEXT_PREFIX" : "",
      "DOCUMENT_ROOT" : "/home/tstdomain1/public_html/wordpress",
      "GATEWAY_INTERFACE" : "CGI/1.1",
      "HTTP_ACCEPT" : "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
      "HTTP_ACCEPT_ENCODING" : "gzip, deflate",
      "HTTP_ACCEPT_LANGUAGE" : "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7",
      "HTTP_CACHE_CONTROL" : "max-age=0",
      "HTTP_CONNECTION" : "keep-alive",
      "HTTP_COOKIE" : "csrftoken=IMrTURlxAxlJ28JXQePuO4T7bNrPsR2NKFDEqaPOucEmGS5s1myOwEYzM5YwIoQK; sessionid=ko18wafadunrfpfcer287mtrcksunu16",
      "HTTP_HOST" : "wordpress.testdomain1.com",
      "HTTP_ORIGIN" : "http://wordpress.testdomain1.com",
      "HTTP_REFERER" : "http://wordpress.testdomain1.com/admin/cpanel/test_b/add/",
      "HTTP_UPGRADE_INSECURE_REQUESTS" : "1",
      "HTTP_USER_AGENT" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36",
      "PATH" : "/usr/local/jdk/bin:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/
      "PATH_INFO" : "/cpanel/test_b/add/",
      "PATH_TRANSLATED" : "/etc/test.sh",
      "QUERY_STRING" : "",
      "REDIRECT_STATUS" : "302",
      "REMOTE_ADDR" : "10.102.1.19",
      "REMOTE_PORT" : "35258",
      "REQUEST_METHOD" : "POST",
      "REQUEST_SCHEME" : "http",
      "REQUEST_URI" : "/admin/cpanel/test_b/add/",
      "SCRIPT_FILENAME" : "/home/tstdomain1/public_html/wordpress/admin",
      "SCRIPT_NAME" : "/admin",
     "SERVER_ADDR" : "192.168.245.54",
      "SERVER_ADMIN" : "webmaster@wordpress.testdomain1.com",
      "SERVER_NAME" : "wordpress.testdomain1.com",
      "SERVER_PORT" : "80",
      "SERVER_PROTOCOL" : "HTTP/1.1",
      "SERVER_SIGNATURE" : "",
      "SERVER_SOFTWARE" : "Apache",
      "UNIQUE_ID" : "XT66dLO1Ikhzi491scvc7wAAAAA"
   },
   "generic_app" : false,
   "group" : "tstdomain1",
   "group_uuid" : "r7jPIf55F53BteJ1LVNr",
   "gupid" : "18dd870-nRuffANZJq",
   "instance_dir" : "/var/passenger/passenger.OXcZTLx",
   "integration_mode" : "apache",
   "load_shell_envvars" : true,
   "log_file" : "",
   "log_level" : 7,
...

And here is the header data that is passed to the application:

[ D3 2019-07-29 05:20:55.6964 956299/T5 age/Cor/Con/SendRequest.cpp:185 ]: [Client 1-1] Header data: "\000\000\013\245REQUEST_URI\000/admin/cpanel/test_b/add/\000PATH_INFO\000/admin/cpanel/test_b/add/\000SCRIPT_NAME\000\000QUERY_STRING\000\000REQUEST_METHOD\000POST\000SERVER_NAME\000wordpress.testdomain1.com\000SERVER_PORT\00080\000SERVER_SOFTWARE\000Apache/2.4.39 (cPanel) OpenSSL/1.0.2s mod_bwlimited/1.4 Phusion_Passenger/5.3.7\000SERVER_PROTOCOL\000HTTP/1.1\000REMOTE_ADDR\00010.102.1.19\000REMOTE_PORT\00035258\000CONTENT_TYPE\000multipart/form-data; boundary=----WebKitFormBoundarynL8BLCF9qiUVIzir\000CONTENT_LENGTH\00057035\000PASSENGER_CONNECT_PASSWORD\000MxDLMbPNwRbcjqXt\000HTTP_USER_AGENT\000Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36\000HTTP_CACHE_CONTROL\000max-age=0\000HTTP_ACCEPT_ENCODING\000gzip, deflate\000HTTP_REFERER\000http://wordpress.testdomain1.com/admin/cpanel/test_b/add/\000HTTP_ACCEPT\000text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3\000HTTP_ACCEPT_LANGUAGE\000ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7\000HTTP_ORIGIN\000http://wordpress.testdomain1.com\000HTTP_COOKIE\000csrftoken=IMrTURlxAxlJ28JXQePuO4T7bNrPsR2NKFDEqaPOucEmGS5s1myOwEYzM5YwIoQK; sessionid=ko18wafadunrfpfcer287mtrcksunu16\000HTTP_HOST\000wordpress.testdomain1.com\000HTTP_UPGRADE_INSECURE_REQUESTS\0001\000UNIQUE_ID\000XT66dLO1Ikhzi491scvc7wAAAAA\000GATEWAY_INTERFACE\000CGI/1.1\000SERVER_PROTOCOL\000HTTP/1.1\000REQUEST_METHOD\000POST\000QUERY_STRING\000\000REQUEST_URI\000/admin/cpanel/test_b/add/\000SCRIPT_NAME\000/admin\000PATH_INFO\000/cpanel/test_b/add/\000PATH_TRANSLATED\000/home/tstdomain1/public_html/wordpress/cpanel/test_b/add/\000HTTP_HOST\000wordpress.testdomain1.com\000HTTP_CONNECTION\000keep-alive\000CONTENT_LENGTH\00057035\000HTTP_CACHE_CONTROL\000max-age=0\000HTTP_UPGRADE_INSECURE_REQUESTS\0001\000HTTP_USER_AGENT\000Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36\000HTTP_ORIGIN\000http://wordpress.testdomain1.com\000CONTENT_TYPE\000multipart/form-data; boundary=----WebKitFormBoundarynL8BLCF9qiUVIzir\000HTTP_ACCEPT\000text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3\000HTTP_REFERER\000http://wordpress.testdomain1.com/admin/cpanel/test_b/add/\000HTTP_ACCEPT_ENCODING\000gzip, deflate\000HTTP_ACCEPT_LANGUAGE\000ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7\000HTTP_COOKIE\000csrftoken=IMrTURlxAxlJ28JXQePuO4T7bNrPsR2NKFDEqaPOucEmGS5s1myOwEYzM5YwIoQK; sessionid=ko18wafadunrfpfcer287mtrcksunu16\000PATH\000/usr/local/jdk/bin:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/usr/local/bin:/usr/X11R6/bin:/root/bin:/opt/bin\000SERVER_SIGNATURE\000\000SERVER_SOFTWARE\000Apache\000SERVER_NAME\000wordpress.testdomain1.com\000SERVER_ADDR\000192.168.245.54\000SERVER_PORT\00080\000REMOTE_ADDR\00010.102.1.19\000DOCUMENT_ROOT\000/home/tstdomain1/public_html/wordpress\000REQUEST_SCHEME\000http\000CONTEXT_PREFIX\000\000CONTEXT_DOCUMENT_ROOT\000/home/tstdomain1/public_html/wordpress\000SERVER_ADMIN\000webmaster@wordpress.testdomain1.com\000SCRIPT_FILENAME\000/home/tstdomain1/public_html/wordpress/admin\000REMOTE_PORT\00035258\000PATH_TRANSLATED\000/etc/test.sh\000REDIRECT_STATUS\000302\000"

As you can see the values ​​of variables such as PATH_INFO and SCRIPT_NAME are duplicated but with different values.

First case:

PATH_INFO\000/admin/cpanel/test_b/add/\000
SCRIPT_NAME\000\000

Second case:

SCRIPT_NAME\000/admin\000
PATH_INFO\000/cpanel/test_b/add/\000

The application itself starts working with values from the second case, which actually breaks it.
If I disable the mod_security, the values ​​from the second case will simply disappear.

The following patch can be applied as a solution to that issue.

--- a/src/apache2_module/Hooks.cpp      2013-10-26 20:00:00.000000000 -0400
+++ b/src/apache2_module/Hooks.cpp      2019-07-29 05:03:13.994176716 -0400
@@ -1009,6 +1009,10 @@ private:
                        env = (apr_table_entry_t*) env_arr->elts;

                        for (i = 0; i < env_arr->nelts; ++i) {
+                               if (strcmp(env[i].key, "SCRIPT_NAME") == 0)
+                                       continue;
+                               if (strcmp(env[i].key, "PATH_INFO") == 0)
+                                       continue;
                                envvarsData.append(env[i].key);
                                envvarsData.append("\0", 1);
                                if (env[i].val != NULL) {

Here:

envvarsData.append(env[i].key);

@CamJN
Copy link
Contributor

CamJN commented Feb 4, 2020

mod_security is setting incorrect values for those env vars, that's something that should be fixed on their end.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants