How to prevent CRLF injection (Http response splitting) in php - php

I did R&D on prevention of CRLF injection in php, but i didn't find any solution in mycase, as I'm using a burp suite tool to inject some headers using CRLF characters like the below.
// Using my tool i put CRLF characters at the start of my request url
GET /%0d%0a%20HackedHeader:By_Hacker controller/action
//This generates an header for me like below
HackedHeader:By_Hacker
So i can modify all headers by doing just like above
This tool is just like a proxy server so it catches the request and gives the response and we can modify the response in the way we want.
So i'm just modifying the response by injecting some headers using CRLF characters. Now the Server responds to this request by injecting the CRLF characters in the response.
I'm just worried as header fields like Pragma, Cache-Control, Last-Modified can lead to cache poisoning attacks.
header and setcookie contain mitigations against response/header splitting, But these can't support me in fixing the above issue
Edit
When i request to mysite.com contact us page like below This is the request I captured in my tool like below
Request headers:
GET /contactus HTTP/1.1
Host: mysite.com
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
And i get the Response HTML for the above request
Now for the same request using the tool i'm adding custom headers just like below
Request Headers:
GET /%0d%0a%20Hacked_header:By_Hacker/contactus HTTP/1.1
Host: mysite.com
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Response Headers:
HTTP/1.1 302 Found
Date: Fri, 10 Jul 2015 11:51:22 GMT
Server: Apache/2.2.22 (Ubuntu)
Last-Modified: Fri, 10 Jul 2015 11:51:22 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Location: mysite.com
Hacked_header:By_Hacker/..
Vary: Accept-Encoding
Content-Length: 2
Keep-Alive: timeout=5, max=120
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8
You can see the injected header Hacked_header:By_Hacker/.. in the above response
Is there anyway in php or apache server configuration to prevent such kind of headers' hack?

Not sure why all the down votes - infact, it is an interesting question :)
I can see that you have tagged CakePHP - which means your app is using Cake Framework... Excellent! If you are using Cake 3 , it is automatically strip off : %0d%0a
Alternatively, where you receive the response header, just strip off %0d%0a and you are good!
Where things like these could be applied - a 3rd party API response or say.... a Webhook response! or a badly sanitized way to handle intl.. example : lang=en to lang=fr where the GET param is directly set as response header... That would not be a wise move!
Ideally, the responses will be as GET and not in the header but either way just strip the %0d%0a and you are good.
Answering your edit.
You can see the injected header Hacked_header:By_Hacker/.. in the above response
That injected header cannot be controlled or stopped, mate. We do not have control over what the other server does.
The question is.. What do you do with the response header?
The answer is... You sanitize it, as ndm said you need to sanitize the input.. What you get as a response IS an input. As soon as you detect %0d%0a, discard the response.
Need code work?
<?php
$cr = '/\%0d/';
$lf = '/\%0a/';
$response = // whatever your response is generated in;
$cr_check = preg_match($cr , $response);
$lf_check = preg_match($lf , $response);
if (($cr_check > 0) || ($lf_check > 0)){
throw new \Exception('CRLF detected');
}

Related

What type of API is this?

Create a very simple form (no styling required) on your own environment to
integrate into our Webservice API using HTTP POST.
I have written a simple application using Zend Framework 2. The application creates a form that once validated is to be sent to a "Webserver API via HTTP POST" to receive a response.
I would like query the API in the correct way as I am very much a believer in protocols and standards.
My following code works for validating the form:
zf-skeleton/module/MyApplication/src/MyApplication/Controller/IndexController.php
public function submitAction() {
$myForm = new MyForm();
$myForm->get('submit')->setValue('Add');
$request = $this->getRequest();
if ($request->isPost()) {
$myModel = new MyModel();
$myForm->setInputFilter($myModel->getInputFilter());
$myForm->setData($request->getPost());
if ($myForm->isValid()) {
// Form is validated. [1]
Once the form has been validated I would like to know the best way to send the form data to the "Webserver API via HTTP POST" and handle the response
What kind of service am I connecting to?
My request headers:
GET /api?foo=1&bar=2 HTTP/1.1
Host: [theservice]
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:39.0) Gecko/20100101 Firefox/39.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: [my cookies]
Connection: keep-alive
The response headers:
HTTP/1.1 200 OK
Date: Tue, 23 Feb 2016 12:58:18 GMT
Content-Type: text/xml
Content-Length: 343
Connection: keep-alive
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Set-Cookie: [Cookie data]
Vary: Accept-Encoding
Content-Encoding: gzip
Server: cloudflare-nginx
If I put into my browser:
http://theservice/api?foo=1&bar=2
I get the response formatted in XML:
<response>
<validresponse>YES</validresponse>
<foo>21</foo>
<bar>21</bar>
</response>
Is it SOAP , REST, neither or unknown?
Rest can generate response both in xml and json. So we cannot rule out REST necessarily.
It is very REST in my opinion.
I'd like to say that it's unknown. You can't say that REST use only JSON format because it can also use XML. IMO you can say that's endpoint which return some data in XML format.

How to get Rid of the JSON Error in Firefox

My Response Header is
Access-Control-Allow-Meth... GET, POST
Access-Control-Allow-Orig... *
Cache-Control no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Connection Keep-Alive
Content-Length 81
Content-Type text/html
Date Mon, 26 Aug 2013 06:35:53 GMT
Expires Thu, 19 Nov 1981 08:52:00 GMT
Keep-Alive timeout=5, max=99
Pragma no-cache
Server Apache/2.4.3 (Win32) OpenSSL/1.0.1c PHP/5.4.7
X-Powered-By PHP/5.4.7`
And The Request Header is
Accept application/json, text/javascript, */*; q=0.01
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Cache-Control no-cache
Connection keep-alive
Content-Length 31
Content-Type application/x-www-form-urlencoded; charset=UTF-8
Cookie USERNAMEEMAIL=shan%40atlos.com; PHPSESSID=8asm46iltcqc9oahsbaaap1c16
Host localhost
Pragma no-cache
Referer http://localhost/test/
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0
X-Requested-With XMLHttpRequest`
i am getting error in firefox "Not Well Formed" what is the problem in this.
i am getting the data correctly in json form but it show also error that is very annoying
Java Script Code to Make Request
GetTopNotification
And Uses a Class for make Ajax Request is
Workspace
Your reponse-header is incorrect.
if(headers_sent()) die('Should not output data before json');
header('Content-type: application/json');
echo json_encode($data_for_json);
exit;
Also, nothing should be sent before the json, and nothing after it either.
In response to comment below:
Somewhere in your php-code you're outputting json. However, as stated, your reponse header is incorrect: the Content-type part should be set to application/json; the above code does just that. A line-by line walktrough:
Checks if you did not already send anything and die if you did
Set the Content-type part of your response header to the appropriate mime-type
Output the json (as it currently is, should be fine)
exit;
More update irt comments
You're creating your json string manually: something i can wholeheartedly advice against, use an array or object and then use json_encode to create you json.
I also added output_buffering over your code, just in case.
Give it a try, new code is here
Update three
In work-space.js Replace this line
self.responseValue = self.getValueFromResponse( jqXHR );
With this
if(type != 'xml') self.responseValue = data;
else self.responseValue = self.getValueFromResponse( jqXHR );
save it, clear the cache, and try again.

HTTP transfert encoding chunked decode PHP

I have this HTTP response content :
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked
Date: Mon, 12 Aug 2013 15:08:10 GMT
PK�Ctemps_attente.json���n� �߅9�Bw���VU��Uߠs���^��#�CGç��ͷ�r7G�3Hnp����^pYSu\#Qo%~x��FGa�Y�ا����S���-ua���t��j-���s�%э��+,g�xq.��������t�fb� �0:)�:�K�}^�N�L����>�֌щ%#�̲x`C#��m݃ :^��$~�i8���WzCh�a�ă���7t�O|��AX˂��UO$���<��y"�;�'F��]��{֘Ha}F��<��l6��o벰V���66t�&��f�Ť��x�H��툗���/PKA�Y�1�PK�CA�Y�1�temps_attente.jsonPK#q
I would like to know what format is the response and how to decompile to have the final response.
I tried to use this function: http_chunked_decode but I did not succeed.
The body (or at least what appears to be the body) of the response is not chunked.
It does appear to be compressed - with HTTP this should be expressly stated in the headers,
There is no blank line between the what appears to be the headers and what appears to be the body.
If this is really the response you are getting it's not HTTP - an off-the-shelf function is not going to make sense of it.

How to tell ZF2's JsonModel to return text/plain instead of application/json?

Using PHP Zend Framework 2.0.2, I return JSON data after an AJAX call. Obviously, Internet Explorer 9 wants to download the data instead of returning it to the calling Javascript method.
Posts like this one and this one say to use Content-Type: text/plain instead of Content-Type: application/json, but how do I do this with ZF2's JsonModel? I'm new to it...
I imagine I have to set something in the setOptions() array, but what?
public function testJsonAction()
{
$jsonResponse = new JsonModel(array('success' => false));
$jsonResponse->setOptions(array(
// ** Should I put something here? What? **
));
return $jsonResponse;
}
I tried using these:
$this->getResponse()->getHeaders()->addHeaderLine('Content-Type', 'text/plain');
$this->getResponse()->getHeaders()->addHeaderLine('Content-Disposition', 'inline; filename="textdata.json"');
but it doesn't change the HTTP Content-Type in the response headers:
Key Value
Response HTTP/1.1 200 OK
Content-Type application/json
Server Microsoft-IIS/7.5
X-Powered-By PHP/5.3.13
Set-Cookie ZDEDebuggerPresent=php,phtml,php3; path=/
Content-Disposition inline; filename="textdata.json"
X-Powered-By ASP.NET
Date Wed, 10 Oct 2012 13:19:42 GMT
Content-Length 17
Thanks for your help!
Because when \Zend\Mvc\MvcEvent::EVENT_RENDER event happen, the JsonStrategy will change content-type again. Source code is in
Zend\View\Strategy\JsonStrategy->injectResponse();
So in order to replace content-type into yours, you need to use EventManager to inject your custom header after JsonStrategy injected.
try below codes in your controller:
$this->getServiceLocator()->get('Application')->getEventManager()->attach(\Zend\Mvc\MvcEvent::EVENT_RENDER, function($event){
$event->getResponse()->getHeaders()->addHeaderLine('Content-Type', 'text/plain');
}, -10000);

Error 404 with jQuery Autocomplete JSON referencing external PHP file

I'm been stuck on this problem for a while and I'm pretty sure it must be something quite simple that hopefully someone out there can shed some light on.
So, I'm currently using jQuery UI's Autocomplete plugin to reference and external PHP which gets information from a database (in an array) and sends it to a JSON output.
From my PHP file (search.php) when I do this:
echo json_encode($items);
My output (when looking at the search.php file) is this:
["Example 1","Example 2","Example 3","Example 4","Example 5"]
Which is valid JSON according to jsonlint.com
The problem is that when I use jQuery UI's Autocomplete script to reference the external search.php file, Chrome just gives me the following error:
GET http://www.example.com/search.php?term=my+search+term 404 (Not Found)
I have tried inputting the JSON code straight into the 'Source:' declaration in my jQuery, and this works fine, but it will not read the JSON from the external PHP file.
Please can someone help?
Here's my code:
HMTL
<p class="my-input">
<label for="input">Enter your input</label>
<textarea id="input" name="input"
class="validate[required]"
placeholder="Enter your input here.">
</textarea>
</p>
jQuery
$(function() {
$( "#input" ).autocomplete({
source: "http://www.example.com/search.php",
minLength: 2
});
});
PHP
header("Content-type: application/json");
// no term passed - just exit early with no response
if (empty($_GET['term'])) exit ;
$q = strtolower($_GET["term"]);
// remove slashes if they were magically added
if (get_magic_quotes_gpc()) $q = stripslashes($q);
include '../../../my-include.php';
global $globalvariable;
$items = array();
// Get info from WordPress Database and put into array
$items = $wpdb->get_col("SELECT column FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY column ASC");
// echo out the items array in JSON format to be read by my jQuery Autocomplete plugin
echo json_encode($items);
Result
In browser, when information is typed into #input
GET http://www.example.com/search.php?term=Example+1 404 (Not Found)
Update: the real PHP url is here: http://www.qwota.co.uk/wp/wp-content/themes/qwota/list-comments.php?term=Your
Please help!
UPDATE: ANSWER
The answer to my problem has been pointed out by Majid Fouladpour
The problem wasn't with my code but rather with trying to use WordPress' $wpdb global variable as (as far as I understand) it includes it's own headers, and anything outside of it's usual layout will result in a 404 error, even if the file is actually there.
I'm currently trying to get around the problem by creating my own MySQL requests and not using WordPress's global variables / headers.
PS. Majid, I'll come back and give you a 'helpful tick' once StackOverflow lets me! (I'm still a n00b.)
Are you sure the path source: "http://www.example.com/search.php" is correct?
You have to make sure that the target URL exists. If you are really using http://www.example.com/search.php then, wk, it simply does not exist, so this is why it does not work.
Update
Since you have a real URL that's working (I tested it!), here are a few steps you can take:
Make sure there's no typo. If there's one, fix it.
Make sure you can open that URL from your browser. If you cannot, then you might be having network access problems (firewall, proxy, server permission issues, etc.)
Try redirecting to another know URL, just to make sure. The 404 error is really a "not found" error. It cannot be anything else.
I think the include is the issue. As Majid pointed out... use the below include instead.
include("../../../wp-load.php");
Good luck!
Your apache server is sending wrong headers. Here is a pair of request and response:
Request
GET /wp/wp-content/themes/qwota/list-comments.php?term=this HTTP/1.1
Host: www.qwota.co.uk
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Cookie: __utma=142729525.1341149814.1305551961.1305551961.1305551961.1; __utmb=142729525.3.10.1305551961; __utmc=142729525; __utmz=142729525.1305551961.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
Response headers
HTTP/1.1 404 Not Found
Date: Mon, 16 May 2011 13:28:31 GMT
Server: Apache
X-Powered-By: PHP/5.2.14
X-Pingback: http://www.qwota.co.uk/wp/xmlrpc.php
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0
Pragma: no-cache
Last-Modified: Mon, 16 May 2011 13:28:31 GMT
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
Response body
["Bake 'em away... toys.","Content precedes design. Design in the absence of content is not design, it\u2019s decoration.","Hanging on in quiet desperation is the English way.","I'm a reasonable man, get off my case.","Look at me, Damien! It's all for you!","Never get out of the boat... absolutely god damn right.","That gum you like is going to come back in style.","The secret to creativity is knowing how to hide your sources.","Things could be different... but they're not.","Your eyes... they turn me."]
So, even though you receive back response from the server, it has HTTP/1.1 404 Not Found in the headers. Someone may be able to investigate this and provide a potential reason and solution.

Categories