{"id":1078,"date":"2010-12-10T18:37:37","date_gmt":"2010-12-10T22:37:37","guid":{"rendered":"http:\/\/cd34.com\/blog\/?p=1078"},"modified":"2010-12-10T18:37:37","modified_gmt":"2010-12-10T22:37:37","slug":"hackers-bypass-htaccess-security-by-using-gets-rather-than-get","status":"publish","type":"post","link":"https:\/\/cd34.com\/blog\/web-security\/hackers-bypass-htaccess-security-by-using-gets-rather-than-get\/","title":{"rendered":"Hackers bypass .htaccess security by using GETS rather than GET"},"content":{"rendered":"<p>Last night I received an urgent message from a client.  My machine has been hacked, someone got into the admin area, I need all of the details from this IP.<\/p>\n<p>So, I grepped the logs, grabbed the appropriate entries and saw something odd.<\/p>\n<pre>\r\n1.2.3.4 - - [09\/Dec\/2010:22:15:41 -0500] \"GETS \/admin\/index.php HTTP\/1.1\" 200 3505 \"-\" \"Mozilla\/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.12) Gecko\/20101026 Firefox\/3.6.12\"\r\n1.2.3.4 - - [09\/Dec\/2010:22:17:09 -0500] \"GETS \/admin\/usermanagement.php HTTP\/1.1\" 200 99320 \"-\" \"Mozilla\/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.12) Gecko\/20101026 Firefox\/3.6.12\"\r\n1.2.3.4 - - [09\/Dec\/2010:22:18:05 -0500] \"GETS \/admin\/index.php HTTP\/1.1\" 200 3510 \"-\" \"Mozilla\/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.12) Gecko\/20101026 Firefox\/3.6.12\"\r\n<\/pre>\n<p>A modified snippet of the .htaccess file:<\/p>\n<pre>\r\nAuthUserFile .htpasswd\r\nAuthName \"Protected Area\"\r\nAuthType Basic\r\n\r\n&lt;Limit GET POST>\r\nrequire valid-user\r\n&lt;\/Limit>\r\n<\/pre>\n<p>Of course, we know GETS isn&#8217;t valid, but, why is Apache handing out status 200s and content lengths that appear to be valid?  We know the area was password protected behind .htaccess and with some quick keyboard work we&#8217;ve got a system that properly prompts for Basic Authentication with a properly formed HTTP\/1.0 request.  Removing the &lt;Limit> restriction from the .htaccess protects the site, but, why are these other methods able to pass through?  Replacing GETS with anything other than POST, PUT, DELETE, TRACK, TRACE, OPTIONS, HEAD results in Apache treating those requests as if GET had been typed.<\/p>\n<p>Let&#8217;s set up a duplicate environment on another machine to figure out what Apache is doing.<\/p>\n<pre>\r\ntsavo:~ mcd$ telnet devel.mia 80\r\nTrying x.x.x.x...\r\nConnected to xxxxxxx.xxx.\r\nEscape character is '^]'.\r\nGET \/htpasstest\/ HTTP\/1.0    \r\n\r\nHTTP\/1.1 401 Authorization Required\r\nDate: Fri, 10 Dec 2010 21:29:58 GMT\r\nServer: Apache\r\nWWW-Authenticate: Basic realm=\"Protected Area\"\r\nVary: Accept-Encoding\r\nContent-Length: 401\r\nConnection: close\r\nContent-Type: text\/html; charset=iso-8859-1\r\n<\/pre>\n<p>Let&#8217;s try what they did:<\/p>\n<pre>\r\ntsavo:~ mcd$ telnet devel.mia 80\r\nTrying x.x.x.x...\r\nConnected to xxxxxxx.xxx.\r\nEscape character is '^]'.\r\nGETS \/htpasstest\/ HTTP\/1.0\r\n\r\nHTTP\/1.1 501 Method Not Implemented\r\nDate: Fri, 10 Dec 2010 21:53:58 GMT\r\nServer: Apache\r\nAllow: GET,HEAD,POST,OPTIONS,TRACE\r\nVary: Accept-Encoding\r\nContent-Length: 227\r\nConnection: close\r\nContent-Type: text\/html; charset=iso-8859-1\r\n<\/pre>\n<p>Odd, this is the behavior we expected, but, not what we are experiencing on the client&#8217;s machine.  Digging a little further we look at the differences and begin to suspect the machine may have been compromised.  The first thing that struck was mod_negotiation &#8211; probably not.  mod_actions, maybe, but, no.  DAV wasn&#8217;t loaded, but, Zend Optimizer was on the machine that appeared to have been exploited.  Testing the above script on the client&#8217;s machine resulted in&#8230;. exactly the same behavior &#8212; method not supported.  Testing the directory that was exploited results in the GETS request served as if it was a GET request.<\/p>\n<p>So, now we&#8217;ve got a particular domain on the machine that is not behaving as the config files would suggest.  A quick test on the original domain, and as expected, GETS responds with the data and bypasses the authorization clause in the .htaccess.  Lets try one more test:<\/p>\n<pre>\r\n\r\n# telnet xxxxxx.mia 80\r\nTrying x.x.x.x...\r\nConnected to xxxxxx.xxx.\r\nEscape character is '^]'.\r\nGETS \/zend.php HTTP\/1.1\r\nHost: xxxxxx.xxx\r\n\r\nHTTP\/1.1 200 OK\r\nDate: Fri, 10 Dec 2010 22:02:33 GMT\r\nServer: Apache\r\nVary: Accept-Encoding\r\nContent-Length: 602\r\nConnection: close\r\nContent-Type: text\/html\r\n<\/pre>\n<p>Bingo.  A Zend encoded file handed us an error 200 even though it contained an invalid request method.<\/p>\n<p>The solution in this case was simple, remove the &lt;Limit> clause from the .htaccess.<\/p>\n<p>The question is, is Zend Optimizer actually doing the proper thing here.  Watching Apache with gdb, Zend Optimizer does appear to hook the Apache request handler a bit higher, but why is it attempting to correct an invalid request?<\/p>\n<p>One of the first rules in input validation is validate and reject on error.  Never try to correct the data and accept it.  If you try to correct it and make a mistake, you&#8217;re just as vulnerable and hackers will try to figure out those patterns and add extra escaping into their url request.  In this case, only a few pages were able to be displayed as there were checks to make sure forms were POSTed.  But, the Limit in .htaccess that should have protected the application, didn&#8217;t work as expected because the invalid methods weren&#8217;t specified.<\/p>\n<p>As so many applications on the web generate .htpasswd files with the Limit clause, it makes me wonder how many Zend Encoded applications are vulnerable.  Take a minute to check your systems.<\/p>\n<div style=\"float:left;\">\n<div id=\"fb-root\"><\/div>\n<fb:like href=\"https:\/\/cd34.com\/blog\/web-security\/hackers-bypass-htaccess-security-by-using-gets-rather-than-get\/\" width=\"250\" send=\"false\" show_faces=\"false\" layout=\"button_count\" action=\"recommend\"><\/fb:like>\n<\/div><div style=\"clear:both;\"><\/div>","protected":false},"excerpt":{"rendered":"<p>Last night I received an urgent message from a client. My machine has been hacked, someone got into the admin area, I need all of the details from this IP. So, I grepped the logs, grabbed the appropriate entries and saw something odd. 1.2.3.4 &#8211; &#8211; [09\/Dec\/2010:22:15:41 -0500] &#8220;GETS \/admin\/index.php HTTP\/1.1&#8221; 200 3505 &#8220;-&#8221; &#8220;Mozilla\/5.0 [&hellip;]<\/p>\n<div style=\"float:left;\">\n<div id=\"fb-root\"><\/div>\n<fb:like href=\"https:\/\/cd34.com\/blog\/web-security\/hackers-bypass-htaccess-security-by-using-gets-rather-than-get\/\" width=\"250\" send=\"false\" show_faces=\"false\" layout=\"button_count\" action=\"recommend\"><\/fb:like>\n<\/div><div style=\"clear:both;\"><\/div>","protected":false},"author":15,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[137],"tags":[9,159,160],"class_list":["post-1078","post","type-post","status-publish","format-standard","hentry","category-web-security","tag-apache","tag-htaccess","tag-zend-optimizer"],"_links":{"self":[{"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/posts\/1078","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/comments?post=1078"}],"version-history":[{"count":5,"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/posts\/1078\/revisions"}],"predecessor-version":[{"id":1083,"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/posts\/1078\/revisions\/1083"}],"wp:attachment":[{"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/media?parent=1078"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/categories?post=1078"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/tags?post=1078"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}