We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 1343 ☆ A M B ☆
    • 2,213 Posts
    If you store this outside the web root it should be safe enough to be effective. You could store a copy of the index.php file and/or other files outside with the security check so you have a "clean" copy to restore should there be any issues.

    I would suggest the index.php and .htaccess files be checked, you could also expand this to cover other "key" files if desired which would be interesting... You could for example check the manager folder as nothing should be changing regularly in there as well.

    Anyways, this looks to be a very interesting approach to the problem.
      Patrick | Server Wrangler
      About Me: Website | Tweets |  MODX Hosting
      • 18913
      • 654 Posts
      Okay, for the "in-file" approach, I had tried to get the checksum analysis done as early in the code execution as possible. So that’s why I had the code in protect.inc.php.

      If we instead move the code to config.inc.php, we gain the use of path settings. So this code
      	
         $pathtoroot = substr($base_path, 0, strpos($base_path, 'public_html'));
         require_once($pathtoroot.'thehash.php');
         $chkmd5return = md5_file('index.php');
         if ($chkmd5return != $md5hash)    
         {
      		$backuprestored = copy($pathtoroot.'indexbackup.php', 'index.php');
      		if ($backuprestored)
      		{
      			header("Location: .");
      		}
      		else
      		{
      			//should log the problem to an error file
      		} 
         }
      


      included in config.inc.php just before the "start cms session" line (in Evo 1.0.4) seems to accomplish the same result. What’s different here is :
      a) the hash is contained in a file ("thehash.php") in a file living above the root,
      and
      b) the known-good file - indexbackup.php - is contained above the root

      This assumes that "public_html" serves to delineate where the "root" starts/ends. So it won’t work on a local install (e.g. XAMPP). Also, this was only tested on one host (Bluehost).

      I haven’t explored inserting/retrieving the same info into/from the MODx database.

      If anyone sees an easier/better way of getting at files outside the root, I’d appreciate hearing about it.
      MattC
        • 20413
        • 2,877 Posts
        Cool stuff! cool
          @hawproductions | http://mrhaw.com/

          Infograph: MODX Advanced Install in 7 steps:
          http://forums.modx.com/thread/96954/infograph-modx-advanced-install-in-7-steps

          Recap: Portland, OR (PDX) MODX CMS Meetup, Oct 6, 2015. US Bancorp Tower
          http://mrhaw.com/modx_portland_oregon_pdx_modx_cms_meetup_oct_2015_us_bancorp_tower
          • 3749
          • 24,544 Posts
          Very nice. cool

          I’d suggest putting the clean index and checksum in or under the core directory. That way they can be found on *any* install by looking at config.core.php.

          Since the Revo core can be located above the web root, they would be in a safe place.
            Did I help you? Buy me a beer
            Get my Book: MODX:The Official Guide
            MODX info for everyone: http://bobsguides.com/modx.html
            My MODX Extras
            Bob's Guides is now hosted at A2 MODX Hosting
            • 18913
            • 654 Posts
            I’m not sure I’m following you Bob as I’ve only been working with Evo. Sounds like your suggestion is Revo-specific. Or have I missed something?

            Another approach that works is to put the whole thing in a function in a file which is located in an include directory for PHP. So then we’re reduced to specifying the file in an include statement and then calling the function. As long as those upper level folders are okay, there would be no way for anyone looking at the MODx code to tell what checksums are being used (e.g. MD5 vs SHA1 vs ?), what files or even folders are being tested, or what action beyond restoring good backups is being taken. Heck, you could even turn the tables a bit and put the function into that base64/encode/decode voodoo that the function evals. With random miscellaneous comments tossed into it, there wouldn’t be a unique signature for a script to look for. At least that’s my initial reaction ...

            MattC
              • 3749
              • 24,544 Posts
              Quote from: mconsidine at Aug 30, 2010, 03:36 PM

              I’m not sure I’m following you Bob as I’ve only been working with Evo. Sounds like your suggestion is Revo-specific.

              Yes, it is.
                Did I help you? Buy me a beer
                Get my Book: MODX:The Official Guide
                MODX info for everyone: http://bobsguides.com/modx.html
                My MODX Extras
                Bob's Guides is now hosted at A2 MODX Hosting
                • 18913
                • 654 Posts
                Still thinking about this, it occurs to me that in the case of Evo all this could be handled by a plugin possibly.

                Does anyone know how early/where the event OnLoadWebDocument is triggered? Or put differently, what would be the earliest appropriate event to trigger the checksum analysis on? Finally, is there a reason that having it trigger on one of these events would *not* make sense or be disadvantageous?

                Obviously, the attraction here is that all the info is stored in the MODx database ...
                MattC
                  • 18913
                  • 654 Posts
                  Looks like the event OnWebPagePrerender might do the trick, though I still don’t know if it gets called early enough...
                  MattC
                    • 18913
                    • 654 Posts
                    A plugin version (Evo 1.0.4 and prior, I’d guess) :
                    $md5hash = 'your_checksum_from_above';  //could get this from the DB if stored there
                    $chkmd5return = md5_file('index.php');
                    if ($chkmd5return != $md5hash)    
                       {
                                    $pathtoroot = substr(MODX_BASE_PATH, 0, -strlen(MODX_BASE_URL)) . '/';
                                    if (strpos($pathtoroot,'public_html')>0 ) $pathtoroot = substr(MODX_BASE_PATH, 0, strpos(MODX_BASE_PATH, 'public_html'));
                                    //if backup copy is buried above the root in a subfolder, append that here
                    		$backuprestored = copy($pathtoroot.'indexbackup.php', 'index.php');  //assumes you named backup copy indexbackup.php
                                    $emailaddy = '[email protected]';
                    		if ($backuprestored) 
                    		{
                                            $message = 'Backup restored for '.MODX_SITE_URL;
                    			header("Location: .");
                    		}
                    		else
                    		{
                                            $message = 'Tried to restore backup copy but failed for '.MODX_SITE_URL;
                                            //try a backup plan?
                                            //how log message to system?
                    			//should log the problem to an error file
                    		} 
                                    mail($emailaddy,'Checksum analysis',$message);
                       }
                    


                    I think this accomodates testing on a local install like XAMPP as well as a live version.

                    What I did was save this as a plugin and select OnWebPagePrerender under System Events as the trigger. So no systems files were messed with.

                    EDIT : It looks like OnWebPageInit is the first event unconditionally invoked.

                    Does anyone know if this would be getting called early enough in the code execution to prevent any hacked code from getting executed? Or, rather, what does go on prior to this event?

                    MattC
                    PS FWIW, I tried storing the backup copy in the database and writing it to disk, but ran into a permissions problem. Probably a good thing ...
                    Edit : fix of typo in question, revised event name used
                      • 18913
                      • 654 Posts
                      It looks like OnWebPageInit is the earliest event invoked. And that happens with the executeParser call. *That* however, is technically conditional. I’m starting to like better the idea of mod’ing one of the php files to pull the code and backup in from above the root.
                      MattC