PHP-Nuke and other installers

Discussion in 'Developers' Forum' started by danf.1979, Dec 23, 2005.

  1. danf.1979

    danf.1979 ISPConfig Developer ISPConfig Developer

    Ok, I agree with all you've said, but talking only about the reseller I see the following problem:
    Suppose a reseller has all the tipical limitations ispconfig can give him, plus 20 CMS.
    He's got 4 different plans. Now, what is the poor man going to do if the 20 CMS are over? I mean, maybe the reseller has a comertial website with his plans for everyone to see. If CMS's are over, will he be "buying" from the ispconfig admin more CMS's? or will he be modifying his plans?
    I think 1 CMS per MySQL is a good choice, and reseller is CMS 1 or 0, but not number limited.
    What do you think? Maybe the reseller problem has a solution, i dont know.
  2. till

    till Super Moderator Staff Member ISPConfig Developer

    Ok, if we limit it by 1 cms = 1 mysql db, then we can limit the number of CMS by the number of databases. Thats fine too.
  3. danf.1979

    danf.1979 ISPConfig Developer ISPConfig Developer

    deleted... sorry. This question was my own mistake.
    Last edited: Jan 30, 2006
  4. danf.1979

    danf.1979 ISPConfig Developer ISPConfig Developer

    Hi to all.
    I was just wondering about a *maybe* quota problem.

    Some CMS allow uploads to certain directories, so those dirs must be world writeable. For example, CMS Made Simple allow creating directories under the upload directory, which is world writeable. Created directories are being created with owner www-data and group www-data.

    My question is, do this newly created directories or uploaded files count for the quota's client? I dont think so, but I'm not really sure.

    If they are not, is there any way to fix this?
  5. till

    till Super Moderator Staff Member ISPConfig Developer

    Files that belong to www-data do not coun to the web quota.

    Yes. But the fix is more related to your setup then to ISPCOnfig.

    If you run PHP either via SuPHP or as PHP CGI with SuExec, all scripts where running under the username of web admin and not as www-data. Then all files created by CMS systems belong to the correct group and user and count to the qouta.

    The drawback with SuPHP and CGI-PHP is that you loose some performance compared to mod_php.

    Another possible solution might to work with PHP as fastCGI, but never tested that and it shall be not so easy to setup.
  6. danf.1979

    danf.1979 ISPConfig Developer ISPConfig Developer

    Uhm ok thanks. The solution is not simple because doing what you say would imply that every cms would create new folders with the right owner but the user would be unable to upload files to it because folders dont get created world writeable by the cms. Maybe a cron job would do the trick, but I'm not solving this problem right now.

    I wanted to aske you something Till (or someone who knows, falko for ex). I got this code:
    		$get_all_db = $go_api->db->queryAllRecords("SELECT * FROM isp_isp_datenbank where doctype_id = 1029 and web_id = $web_id");
    		foreach($get_all_db as $db) {
    					$dbs .= '
    					<tr style="background-color: #666666;"> 
    					<td colspan="2"><span style="font-weight: bold; color: white; font-size: 13px;">
    					<div style="margin-left: 40px;"><input name="db_database" type="radio" value='.$db["datenbankname"].'>&nbsp;&nbsp;'.$db["datenbankname"].'</div></span> </td>
    It generates radio buttons for the database for a given web_id. I'm not quite sure I understand the doc_id right now, I'm really being fixing and optimizing the installer code. I implemented a class for the cms_installer.php file (my own writeconf.php) but I use global statements on the methods of the class. I dont know if that would be the "correct" thing to do, but they manage to get the cms installed and that class serves to install like 10 cms rght now. Maybe you could comment on this?
    Ok, back to the code. I dont really know if always a database gets installed with a 1029 doctype_id and I think that that would be the only possible failure of the mysql query right now.
    I have done a very nice template for the cms installer (i think its pretty), but I know that there are other people who can do much better templates than me with css for example. Maybe some volunter to get css on this? anyone?
    Ok thanks.
    Oh, another question. Do i have to code some stuff to prevent sql injection in the various forms I use? I have never done this so thats why I ask. I dont know if is enough with the *general* security platform that ispconfig provides to my script.
  7. danf.1979

    danf.1979 ISPConfig Developer ISPConfig Developer

    Oh, something else I want to comment (not really needed right now though).
    I think of ISPConfig to be the better code I've seen. Maybe it is not my code style, but I think the relationships between the scripts, the database and the daemons are really very very clever. I have little experience to say that though, and I just know little about ISPConfig code, just what I've needed to code my own script.
    I have my own daemon checking for its own .signal files. With that I've managed to get a root script executed and the cms identified. I know I could do the identification with only the database, but till now the sistem works ok and the code is not very extense.
    For example, cms_installer.php (my own writeconf.php) is about 275 lines, maybe 250 or 240 of code. It detects the signal file, makes necessary querys, define all necesary variables for each cms installation, and executes the install class. The install class is another script (59 lines) that executes create directories, copy, chmod, chown, rm stuff, makes the config file of the cms, gets mysql stuff done, etc.
    I have done a very singular thing for the getting all this thing working. I install the cms, erase all customized field in mysql and export the sql to a file. Then even may be able of customizing this setups with new templates, pages or modified languaje files with better names and explanations for the translations. Most all of them are with the default installation though (but with my own database dump). I have most cms with default installation though, I havent have the time to make this on all cms ofcourse. With this I have been able to forgot completely about defaults installers. I maybe able in the future to choose a custom language for the cms installation, I dont know. Many things can be done with this thing I guess. I even want to make simple mysql controls for the cms manager so mysql dabase creation, cms deletions, maybe updates also, as I said, I dont know really yet what to do first. And also, I am right now optimizing code and making modifications.

    How do you want to get this on ispconfig? I mean, it works in my installation, but how is the coordination for controling the possible cms to get installed going to be? Maybe I can do that with some classification in mind. I wanto to classify the cms to different classes by cms type (forum, portal, chat, etc) and with that in mind make the mysql limitations. For example, 1 MySQL permits 1 cms, and that limitation would permit only one installation for the portal, but little forum and live support center cms are too included by default. General idea would be making little cms software world wide available and bigger cms limitated. I know it can be also user configured but I will not code this in the short term.
    Last edited: Feb 4, 2006
  8. till

    till Super Moderator Staff Member ISPConfig Developer

    IIf you use suexec + cgiphp or suphp, the cms runs under the username of the web admin and not the apache user, so these problems dont exist and the directories must not be world writable.

    if you dont use suexec + cgiphp or suphp, the direcories must be world writable.

    The doc_id is always the primary ID of a table. As the doctype_id for mysql databases is always 1029, you can optimize the query like this, but it does not harm if let it like it is now :)

    SELECT * FROM isp_isp_datenbank where web_id = $web_id

    Generally it is better to avoid global variables. If the codebase grows you will get lesser variable conflicts. But you dont have to change your code now, if it works.

    yes, databases have always the same doctype_id 1029.

    If your form is not completely generated by the form designer, you have to check all variables against SQL injection. The most secure way is by checking the values with regular expressions and escape strings correctly with the function $go_api->db->quote(".......");
  9. webstergd

    webstergd ISPConfig Developer ISPConfig Developer

    global variables, undeclared variables, and variables that are sent with post, get, cookies(basicly from the client to the server) would be the first thing an attacker will look for. It is highly recomended to never use global variables unless you really really really need to. If you do these methods you must check the variables really well.

    For example, even if your variable is only used to grab an image(or just display the image name) and post it, you are running the risk of XSS attack. This was a huge problem with PostNuke, EasyNews php, webalizer, GNU Mailman, mp3 files and all sorts of programs out there. This type of attack isn't limited to images, really anythign that is posted.
    (just wanted to provide an example of how dangerious user variables can be)

    As till said, dont worry about changing your code if it works. I am currently going through the code, with time permitting , to help secure it.

    Awesome work though. Thank you so much for doing that. If you need any help I am more then happy to help.
  10. danf.1979

    danf.1979 ISPConfig Developer ISPConfig Developer

    Ok thanks to you too. I'll be posting soon because my class works, but I'm using too much globals on some methods in the class. I have only programmed classes in Python and I did not use globals, but I'm rather new to php. I was looking at this moment how vars are assigned to a given class in writeconf.php. I was not aware of the sintax to do that. I think thats how I can prevent extensive use of globals. I'll give it a try right now.
    I have read also something about cross site scripting and some general security topics, but I'm not on it right now. I have other things to finish yet, but I wasnt aware of those topics, so thanks. ;)
  11. danf.1979

    danf.1979 ISPConfig Developer ISPConfig Developer

    Yes I confused me. Any drawbacks from running with those moduls? Would I have to change something in the cms installer or is it just like an apache config? Would some cms stop running? :confused: I have never used those modules. Thanks.

    Note: There is another post to webstergd before this one
    Last edited: Feb 6, 2006
  12. webstergd

    webstergd ISPConfig Developer ISPConfig Developer

    possible idea...

    do we have a folder or group in cvs for mod's or extra's? Might be easier for people to help with? Especially with tortoiseSVN that program is awesome...thanks for teh recomendation till.

    Would it be wise to make a closed forum that only developers can read and access? We could use this for for security fixes and questions of that nature. Might be wise to restrict this to select developers who are active or "trusted."

    And dude I am so looking fwd to your mod. I think it will be a huge boost for ispconfig. WAY TO GO!
  13. danf.1979

    danf.1979 ISPConfig Developer ISPConfig Developer

    Hi again. I just staring at the code right now and got a little scared with the function that deletes directories from a cms created installation.
        function _do_delete() {
            if ( 
    is_array($this->do_delete) ) {    
                foreach (
    $this->do_delete as $value) {
    system("rm -rf ".$this->path_to_create."/".$value);
    do_delete is an array of directories to delete: $cms_install->do_delete = array("dir1/", "dir2/");
    How can I be absolutely secure that I will *never* delete my entire disc?
    I do define do_delete only in the script and there is no $_POST var involved, but this could not be the case in the future.
    For example, could I force that all directories to eventually delete *must* be inside, for example, in /var/www/web[ID]/web/ ? (I know it can be other document root too) but just for simplicity
    Last edited: Feb 6, 2006
  14. webstergd

    webstergd ISPConfig Developer ISPConfig Developer

    you were correct in your fear. I am not sure what rights the function would be granted but it could still be a big problem.

    This solution is from the top of my head with only given it a few min through so check it with Till or Falko but here is how I would make it more secure:

    instead of the $value holding the directory you could use $value as a number. Then the number would triger an if statement that would then delete the coresponding directory.

    lets say $value = 2;
    if( value == 1)
    remove rf /var/www/web[id]/web/joomla/
    else if(value == 2)
    remove rf /var/www/web[id]/web/phpbb2/
    error message
    only problem with this is that web[id] would need to be properly checked to make sure it only includes proper characters ([A-Z][a-z][0-9] and I believe '_' check with Till) Have the statement die on any other values detected. Few other checks might be wise to run on web[id]. Till would be your best man to ask about the functions provided by php for this.

    I still dont like web[id] in there but for simplicity sake I am not going to worry.

    Later to make it easier to update you could place the list of directories in a static, readonly, config file and have the program read them and place them in a static array. still need to check the values but this should make it easier to update.
    Last edited: Feb 6, 2006
  15. till

    till Super Moderator Staff Member ISPConfig Developer

    I think the approach from webstergd is more secure. The [ID] from web[id] is always an integer. You can check this either with an regex, e.g. "/^[0-9]{1,10}$/" or you use the fact that a valid [ID] cant be 0, so if you use somthing like $id = intval($id); will convert $id to an valid integer or will result in 0, which is harmless and can be easy filtered by if($id > 0) {....

    For even more security, you might check every path right before the exec statement if it:

    1) Starts with the web docroot (/home/www/ or /var/www or whatever is set in the isp_server table as root directory for the websites.
    2) Does not contain 2 dots ".."
    3) does contain only valid path characters. E.g. not "|<>;" and is escaped by escapeshellcmd.

    Why this extra security?. The CMS installer might be extended later that it installs packeges build by external poeple / projects. If then someone builds a harmful or only lazy build package we must try to limit the possible damage as much as posiible.

    Or am i too paranoid :) ?
  16. danf.1979

    danf.1979 ISPConfig Developer ISPConfig Developer

    Ok, I'm using this now:
        function _do_delete() {
    	$httpd_root = "/var/www"; # This will be taken from isp_server
    	if(stristr($this->path_to_delete, $httpd_root."/web".$this->web_id) == TRUE AND stristr($this->path_to_delete, "..") == FALSE){
    			if ( is_array($this->do_delete) ) {    
    				foreach ($this->do_delete as $value) {
    					print "rm -rf ".$this->path_to_delete."/".$value."<br>";			
    					//system("rm -rf ".$this->path_to_delete."/".$value);
    	else {
    		echo 'Access denied.';
    I dont know what do you mean by this Till: ...and is escaped by escapeshellcmd.
    Thanks both.
  17. webstergd

    webstergd ISPConfig Developer ISPConfig Developer

    ehh better but still has a lot of holes.

    I agree with Till on all his security points and he is a much better php programmer then I am. However, I do not feel his solution will patch all the holes in this statement.

    for example:
    if a users submits .../../../ he will still be able to transverse the directory. The system matches two .. not three. Called triple-dot vulnerablility.

    If a hacker sends the command /var/www/.../../../../../etc/passwd you will have the password file.

    Next example is that if hacker uses multiple alternate encodings for text in order to bypass the filters the filters will not flag.

    /var/www/%25%25/%25%23/%25%25 ...... using URL
    /var/www/%C0AE/%C0AE/%C0AF ......... using unicode

    ok, I am tired so i will stop with the examples...

    basicly my fear is that it is almost impossible to properly search for phrases that are not allowed. Using different encoding tricks or really just playing around you could eventully find a loophole. I am a firm believer on stating what a function can do verses what I function cannot do.

    if I have time later tonight I will think of possible ways to do this that could solve your problem and make the program easier. Might not be as efficient as my original idea but should be just as secure and a hell of a lot easier to program.

    Last edited: Feb 7, 2006
  18. webstergd

    webstergd ISPConfig Developer ISPConfig Developer

    possible other solution way to "secure" your statement

    $value will return a url ... for example purposes we will say /var/www/web[id]/cms

    you could take the variable from $value and match the string exactly with a preset string. If data isn't exact, kill the function.

    if ($value == /var/www/web[id]/cms)
    rm -rf /var/www/web[id]/cms
    else if ($value == /var/www/web[id]/joomla)
    rm -rf /var/www/web[id]/joomla
    in our example the first if statement will return true and
    "rm -rf /var/www/web[id]/cms"
    will execute.

    $value = /var/www/web[id]/cms/"insert something bad here" 
    the command will not execute and you are safe.

    This method will be slower and less efficent then checking the given variables. However, you will not be able to execute a command you might not want to execute such as..

    "rm -rf /var/www/web[id]/cms/../../../../../../../../../../../"
    which is equal to "rm -rf /"

    This solution is also not flexable but we could change that around later by adding how it checks. such as a searching through a static array of possible values. We could build the static array through a read only config file.
  19. till

    till Super Moderator Staff Member ISPConfig Developer

    I dont think that your examples will trick the filters i mentioned above:

    If you have a hard coded path "/var/www/web[id]/cms" where [id] is checked / converted with the intval command or an regex and then it is passed to my filters, i dont see how this can be exploited easily. To the filters:

    1) The double dot filter filters also three and mor dots when you search with stristr(...) function.

    2) The filter for unallowed chars must list escape sequences too, like "%#" and others. I mentioned in my post only a few characters.

    My solution was to use the solution you posted with web[id] as first "firewall" and then double check the string for malicious chars as second check before it is used in the exec statement.

    The problem that i see is when we use only your type of path checking without a second "firewall", where do we get the string "/var/www/web[id]/joomla" from when the joomla package comes from an external package builder? The path string must be included in the package. If we want to have third party packages we either have to allow only "thrusted" packages where a developer from ISPConfig inspects every revision for malicoius code or we have to try to make even the installation from third party packages as secure as possible?
  20. webstergd

    webstergd ISPConfig Developer ISPConfig Developer

    Sorry Till! I miss read the post thinking it was your post verses Dan's. After reading your filters I do see your point, I appologize.

    I cannot find any flaws in your web[id] filter.

    I have your same fear with my filter. If it is done correctly it would be hard to allow others to expand on or allow updates. I would be time consuming to force a check for every revision of the cms's we support. However, would it be unwise to provide trusted cms packages on the website?

    Complete judgement call on your part.

    However, my concern was with $value. I believe holes can be punched through the filters for $value. I need to read the php documentation or ask a friend to make sure about this. But, I beleive escapseshellcmd() in php only filters single characters not double

    % will be kicked out but
    %% will return only a single %

Share This Page