Пример #1
0
 /**
  *UNCATCHABLE ERRORS
  */
 public static function captureShutdown()
 {
     if (defined('_BF_LAST_BREATH')) {
         bfLog::log('Tock with dying breath said:  ' . _BF_LAST_BREATH);
     } else {
         bfLog::log('Tock');
     }
 }
Пример #2
0
 /**
  * deletes a directory recursively
  * Bf_Filesystem::deleteRecursive(JPATH_ROOT .'/tmp', TRUE);
  *
  * @param string $target
  * @param bool   $ignoreWarnings
  * @param array  $msg
  *
  * @return bool
  */
 static function deleteRecursive($target, $ignoreWarnings = FALSE, $msg = array())
 {
     $exceptions = array('.', '..');
     if (!($sourceDir = @opendir($target))) {
         if ($ignoreWarnings !== TRUE) {
             $msg['result'] = 'failure';
             $msg['errors'][] = $target;
             return $msg;
         }
     }
     if (!$sourceDir) {
         return;
     }
     while (FALSE !== ($sibling = readdir($sourceDir))) {
         if (!in_array($sibling, $exceptions)) {
             $object = str_replace('//', '/', $target . '/' . $sibling);
             if (is_dir($object)) {
                 $msg = Bf_Filesystem::deleteRecursive($object, $ignoreWarnings, $msg);
             }
             if (is_file($object)) {
                 bfLog::log('Deleting ' . $object);
                 $result = unlink($object);
                 if ($result) {
                     $msg['deleted_files'][] = $object;
                 }
                 if (!$result) {
                     $msg['errors'][] = $object;
                 }
             }
         }
     }
     closedir($sourceDir);
     if (is_dir($target)) {
         bfLog::log('Deleting ' . $target);
         if ($result = rmdir($target)) {
             $msg['deleted_folders'][] = $target;
             $msg['result'] = 'success';
         } else {
             bfLog::log(sprintf('Deleting %S FAILED', $target));
             $msg['result'] = 'failure';
         }
     } else {
     }
     return $msg;
 }
Пример #3
0
 /**
  * Get a JSON formatted list of installed extensions
  * Needs to be public so we can call it from the audit.
  *
  * @return string
  */
 public function getExtensions()
 {
     // connect/get the Joomla db object
     $this->db = JFactory::getDbo();
     // crazy way of handling Joomla 1.5.x legacy :-(
     $one5 = FALSE;
     // Get Joomla 2.0+ Extensions
     $this->db->setQuery('SELECT e.extension_id, e.name, e.type, e.element, e.enabled, e.folder,
                             (
                              SELECT title
                              FROM #__menu AS m
                              WHERE m.component_id = e.extension_id
                              AND parent_id = 1
                              ORDER BY ID ASC LIMIT 1
                              )
                              AS title
                             FROM #__extensions AS e
                             WHERE protected = 0');
     $installedExtensions = $this->db->loadObjectList();
     // ok if we have none maybe we are Joomla < 1.5.26
     if (!$installedExtensions) {
         // Yooo hoo I'm on a crap old, out of date, probably hackable Joomla version!
         $one5 = TRUE;
         // Get the extensions - used to be called components
         $this->db->setQuery('SELECT "component" as "type", name, `option` as "element", enabled FROM #__components WHERE iscore != 1 and parent = 0');
         $components = $this->db->loadObjectList();
         // Get the plugins
         $this->db->setQuery('SELECT "plugin" as "type", name, element, folder, published as enabled FROM #__plugins WHERE iscore != 1');
         $plugins = $this->db->loadObjectList();
         // get the modules
         $this->db->setQuery('SELECT  "module" as "type", module, module as name, client_id, published as enabled FROM #__modules WHERE iscore != 1');
         $modules = $this->db->loadObjectList();
         /**
          * Get the templates - I n Joomla 1.5.x the templates are not in the
          * db unless published so we need to read the folders from the /templates folders
          * Note in Joomla 1.5.x there was no such think as admin templates
          */
         $folders = array_merge(scandir(JPATH_BASE . '/templates'), scandir(JPATH_ADMINISTRATOR . '/templates'));
         $templates = array();
         foreach ($folders as $templateFolder) {
             $f = JPATH_BASE . '/templates/' . trim($templateFolder);
             $a = JPATH_ADMINISTRATOR . '/templates/' . trim($templateFolder);
             // We dont want index.html etc...
             if (!is_dir($f) && !is_dir($a) || ($templateFolder == '.' || $templateFolder == '..')) {
                 continue;
             }
             if (is_dir($a)) {
                 $client_id = 1;
             } else {
                 $client_id = 0;
             }
             // make it look like we want like Joomla 2.5+ would
             $template = array('type' => 'template', 'template' => $templateFolder, 'client_id' => $client_id, 'enabled' => 1);
             // Convert to an obj
             $templates[] = json_decode(json_encode($template));
         }
         // Merge all the "extensions" we have found all over the place
         $installedExtensions = array_merge($components, $plugins, $modules, $templates);
     }
     $lang = JFactory::getLanguage();
     // Load all the language strings up front incase any strings are shared
     foreach ($installedExtensions as $k => $ext) {
         $lang->load(strtolower($ext->element) . ".sys", JPATH_ADMINISTRATOR, 'en-GB', TRUE);
         $lang->load(strtolower($ext->element) . ".sys", JPATH_SITE, 'en-GB', TRUE);
         $lang->load(strtolower($ext->name) . ".sys", JPATH_ADMINISTRATOR, 'en-GB', TRUE);
         $lang->load(strtolower($ext->name) . ".sys", JPATH_SITE, 'en-GB', TRUE);
         $lang->load(strtolower($ext->title) . ".sys", JPATH_ADMINISTRATOR, 'en-GB', TRUE);
         $lang->load(strtolower($ext->title) . ".sys", JPATH_SITE, 'en-GB', TRUE);
         $lang->load(strtolower($ext->element), JPATH_ADMINISTRATOR, 'en-GB', TRUE);
         $lang->load(strtolower($ext->element), JPATH_SITE, 'en-GB', TRUE);
         $lang->load(strtolower($ext->name), JPATH_ADMINISTRATOR, 'en-GB', TRUE);
         $lang->load(strtolower($ext->name), JPATH_SITE, 'en-GB', TRUE);
         $lang->load(strtolower($ext->title), JPATH_ADMINISTRATOR, 'en-GB', TRUE);
         $lang->load(strtolower($ext->title), JPATH_SITE, 'en-GB', TRUE);
         $element = str_replace('_TITLE', '', strtoupper($ext->element));
         $name = str_replace('_TITLE', '', strtoupper($ext->name));
         $title = str_replace('_TITLE', '', strtoupper($ext->title));
         $lang->load(strtolower($element) . ".sys", JPATH_ADMINISTRATOR, 'en-GB', TRUE);
         $lang->load(strtolower($element) . ".sys", JPATH_SITE, 'en-GB', TRUE);
         $lang->load(strtolower($name) . ".sys", JPATH_ADMINISTRATOR, 'en-GB', TRUE);
         $lang->load(strtolower($name) . ".sys", JPATH_SITE, 'en-GB', TRUE);
         $lang->load(strtolower($title) . ".sys", JPATH_ADMINISTRATOR, 'en-GB', TRUE);
         $lang->load(strtolower($title) . ".sys", JPATH_SITE, 'en-GB', TRUE);
         $lang->load(strtolower($element), JPATH_ADMINISTRATOR, 'en-GB', TRUE);
         $lang->load(strtolower($element), JPATH_SITE, 'en-GB', TRUE);
         $lang->load(strtolower($name), JPATH_ADMINISTRATOR, 'en-GB', TRUE);
         $lang->load(strtolower($name), JPATH_SITE, 'en-GB', TRUE);
         $lang->load(strtolower($title), JPATH_ADMINISTRATOR, 'en-GB', TRUE);
         $lang->load(strtolower($title), JPATH_SITE, 'en-GB', TRUE);
         // templates
         $lang->load('tpl_' . strtolower($name), JPATH_ADMINISTRATOR, 'en-GB', TRUE);
         $lang->load('tpl_' . strtolower($name), JPATH_SITE, 'en-GB', TRUE);
         // Joomla 1.5.x modules
         $lang->load('mod_' . strtolower($name), JPATH_ADMINISTRATOR, 'en-GB', TRUE);
         $lang->load('mod_' . strtolower($name), JPATH_SITE, 'en-GB', TRUE);
         // tut tut Akeeba - bad naming!
         $lang->load(strtolower('PLG_SYSTEM_SRP'), JPATH_ADMINISTRATOR, 'en-GB', TRUE);
         // should be plg_srp
         $lang->load(strtolower('PLG_SYSTEM_ONECLICKACTION'), JPATH_SITE, 'en-GB', TRUE);
         // should be plg_oneclickaction
         $lang->load(strtolower('PLG_SYSTEM_ONECLICKACTION'), JPATH_ADMINISTRATOR, 'en-GB', TRUE);
         // should be plg_oneclickaction
         // Joomla 1.5 plugins
         if ($ext->type == 'plugin') {
             $plg = 'plg_' . $ext->folder . '_' . $ext->element;
             $lang->load(strtolower($plg), JPATH_SITE, 'en-GB', TRUE);
             $lang->load(strtolower($plg), JPATH_ADMINISTRATOR, 'en-GB', TRUE);
         }
         if ($ext->type == 'template') {
             $plg = 'tpl_' . $ext->name;
             $lang->load(strtolower($plg), JPATH_SITE, 'en-GB', TRUE);
             $lang->load(strtolower($plg), JPATH_ADMINISTRATOR, 'en-GB', TRUE);
         }
     }
     // ok now we have the extensions - get the xml for further offline crunching
     foreach ($installedExtensions as $k => $ext) {
         // remove not supported types :-(
         if ($ext->type == 'file' || $ext->type == 'package') {
             unset($installedExtensions[$k]);
             continue;
         }
         $ext->xmlFile = $this->findManifest($ext);
         try {
             if ($ext->xmlFile !== FALSE) {
                 $parts = explode('/', $ext->xmlFile);
                 array_pop($parts);
                 $ext->path = implode('/', $parts);
                 bfLog::log('Loading XML file = ' . str_replace(JPATH_BASE, '', $ext->xmlFile));
                 $xml = trim(file_get_contents($ext->xmlFile));
                 $myXML = new SimpleXMLElement($xml);
                 if (property_exists($myXML, 'description')) {
                     $ext->desc = $myXML->description;
                 }
                 $ext->xmlFileContents = base64_encode(gzcompress($xml));
                 $ext->xmlFileCreated = filemtime($ext->xmlFile);
             } else {
                 $ext->MANIFESTERROR = TRUE;
             }
         } catch (Exception $e) {
             bfLog::log('EXCEPTION = ' . $ext->xmlFile . ' ' . $e->getMessage());
             die('Could not process XML file at: ' . str_replace(JPATH_BASE, '', $ext->xmlFile));
         }
         $ext->name = JText::_($ext->name);
         $ext->title = JText::_($ext->title);
         $ext->desc = base64_encode(gzcompress(JText::_($ext->desc)));
         // remove base paths - we dont want to leak data :)
         $ext->xmlFile = $this->removeBase($ext->xmlFile);
         $ext->path = $this->removeBase($ext->path);
         // Sort so its pretty - not that anyone sees, but debugging is easier
         $ext = (array) $ext;
         ksort($ext);
         // push to the result
         $installedExtensions[$k] = $ext;
     }
     return json_encode($installedExtensions);
 }
Пример #4
0
 /**
  *
  */
 public static function truncate()
 {
     bflog::checkPermissions();
     @unlink('tmp/log.tmp');
     bfLog::log('Log file truncated');
     // populate the config into the log
     bfLog::log('PHP Max Memory = ' . ini_get('memory_limit'));
     bfLog::log('PHP ini_setted Max Time = ' . ini_get('max_execution_time'));
     bfLog::log('PHP bfTimer Max Time = ' . bfTimer::getInstance()->getMaxTime());
 }
Пример #5
0
    private function clearTmpFiles()
    {
        require 'bfFilesystem.php';
        $filesAndFolders = Bf_Filesystem::readDirectory(JPATH_ROOT . '/tmp', '.', true);
        foreach ($filesAndFolders as $pointer) {
            $pointer = JPATH_ROOT . '/tmp/' . $pointer;
            if (is_dir($pointer)) {
                bfLog::log('Deleting ' . $pointer);
                Bf_Filesystem::deleteRecursive($pointer, TRUE);
            } else {
                bfLog::log('Deleting ' . $pointer);
                unlink($pointer);
            }
        }
        file_put_contents(JPATH_ROOT . '/tmp/index.html', '<html><body bgcolor="#FFFFFF"></body></html> ');
        $sql = 'DELETE FROM bf_files WHERE
		          filewithpath LIKE "/tmp%"
		            AND
				  filewithpath != "/tmp/index.html"';
        $this->_db->setQuery($sql);
        $this->_db->query();
        bfEncrypt::reply('success', array('res' => TRUE));
    }
Пример #6
0
 *
 * bfNetwork is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bfNetwork is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this package.  If not, see http://www.gnu.org/licenses/
 */
// Decrypt or die
require 'bfEncrypt.php';
/**
 * If we have got here then we have already passed through decrypting
 * the encrypted header and so we are sure we are now secure and no one
 * else cannot run the code below.....
 * ... ...
 */
// Get the steps
require 'bfStep.php';
// Get the gutsy auditor tool
require 'bfAuditor.php';
// Tick over... inject the decrypted object
$scanner = new bfAudit($dataObj);
// Tick Tock...
bfLog::log('Tick');
$scanner->tick();
Пример #7
0
    /**
     * Find out some basic information about this site and its setup
     */
    private function bestpracticesecurityAction()
    {
        bfLog::log('=============================================');
        bfLog::log('=========bestpracticesecurityAction==========');
        bfLog::log('=============================================');
        $app = JFactory::getApplication('site');
        $this->platform = 'Joomla';
        // Mark PHP in places PHP should not be!
        if ($ids = $this->_phpInWrongPlaces()) {
            $this->db->setQuery("UPDATE bf_files SET `suspectcontent` = 1 WHERE id IN (" . implode(',', $ids) . ")");
            $this->db->query();
        }
        // Remove OUR stuff as we dont need to report on that
        $this->db->setQuery("DELETE FROM bf_files WHERE\n\t\t\t\tfilewithpath = '/plugins/system/j15_bfnetwork.xml'\n\t\t\t\tOR filewithpath = '/plugins/system/j25_30_bfnetwork.xml'\n\t\t\t\tOR filewithpath LIKE '/plugins/system/bfnetwork%'");
        $this->db->query();
        // Remove OUR stuff as we dont need to report on that
        $this->db->setQuery("DELETE FROM bf_folders WHERE folderwithpath LIKE '/plugins/system/bfnetwork%'");
        $this->db->query();
        // Report count of all .htaccess files
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE filewithpath LIKE "%.htaccess"');
        $this->htaccess_files = $this->db->LoadResult();
        // Report count of all files with 777 permissions
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE fileperms LIKE "%777%"');
        $this->files_777 = $this->db->LoadResult();
        // Report count of all folders with 777 permissions
        $this->db->setQuery('SELECT COUNT(*) FROM bf_folders WHERE folderinfo LIKE "%777%"');
        $this->folders_777 = $this->db->LoadResult();
        // Report all hidden folders like .git or .svn
        $this->db->setQuery('SELECT COUNT(*) FROM bf_folders WHERE folderwithpath LIKE "%/.%"');
        $this->hidden_folders = $this->db->LoadResult();
        // Report all hidden files like .htaccess .hack
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE filewithpath LIKE "%/.%"');
        $this->hidden_files = $this->db->LoadResult();
        // Report nested Joomla versions
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE filewithpath LIKE "%/administrator/index.php"');
        $this->nestedinstalls = $this->db->LoadResult();
        // Report file what might have been renamed to hide
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE filewithpath LIKE "%.old%" OR filewithpath LIKE "%.bak%" OR filewithpath LIKE "%.backup%"');
        $this->renamedtohidefiles = $this->db->LoadResult();
        // Report any error_log files
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE filewithpath LIKE "%error_log"');
        $this->error_logs_seen = $this->db->LoadResult();
        // Report files in the /tmp folder
        $this->db->setQuery('SELECT count(*) FROM bf_files WHERE filewithpath LIKE "/tmp%" AND filewithpath != "/tmp/index.html"');
        $this->tmp_install_folders = $this->db->LoadResult();
        // Report any encrypted files
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE encrypted = 1');
        $this->encrypted_files = $this->db->LoadResult();
        // Report suspect files
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE suspectcontent = 1');
        $this->suspectfiles = $this->db->LoadResult();
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE filewithpath LIKE "%php.ini%"');
        $this->phpiniseen = $this->db->LoadResult();
        // has_robots_modified
        $sql = 'SELECT core.hash AS corehash, currenthash AS currenthash FROM bf_core_hashes AS core
                    LEFT JOIN bf_files AS f ON f.filewithpath = core.filewithpath
                    WHERE core.filewithpath = "/%s" OR core.filewithpath = "/%s" LIMIT 1';
        $this->db->setQuery(sprintf($sql, 'robots.txt', 'robots.txt.dist'));
        $row = $this->db->loadAssocList();
        if ($row) {
            if ($row[0]['corehash'] === $row[0]['currenthash']) {
                $this->has_robots_modified = 0;
            } else {
                $this->has_robots_modified = 1;
            }
        } else {
            $this->has_robots_modified = 0;
        }
        // Files over 2Mb
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE SIZE > 2097152');
        $this->large_files = $this->db->LoadResult();
        // Doing this again here now that I refactored the audit for perfomance I now need to do this much later on :-(
        $this->hashfailedcount = $this->gethashfailurecountAction(TRUE);
        // Report if we have default user ids
        $this->user_hasdefaultuserids = $this->_hasDefaultUserids();
        // PhP in wrong places
        $phpInWrongPlaces = $this->_phpInWrongPlaces();
        $this->phpinwrongplace = $phpInWrongPlaces ? count($phpInWrongPlaces) : 0;
        /**
         * @todo add these http://en.wikipedia.org/wiki/List_of_archive_formats
         */
        // Report all archives
        $this->db->setQuery('SELECT COUNT(*) FROM bf_files WHERE
		filewithpath LIKE "%.zip"
		OR filewithpath LIKE "%.tar"
		OR filewithpath LIKE "%.tar.gz"
		OR filewithpath LIKE "%.bz2"
		OR filewithpath LIKE "%.gzip"
		OR filewithpath LIKE "%.bzip2"');
        $this->archive_files = $this->db->LoadResult();
        // ok got this far, toggle to the next step AND sleep
        $this->nextStepPlease(TRUE);
    }
Пример #8
0
 /**
  * Encrypt a string using the RC4 Key provided in the encrypted request
  * from the service backend
  *
  * @param string $msg
  *
  * @return string Base64encoded message
  */
 public static function getEncrypted($msg)
 {
     $start = time();
     bfLog::log('Starting Encryption....');
     // check our msg is a string
     if (is_object($msg) || is_array($msg)) {
         $msg = json_encode($msg);
     }
     // init a RC4 encryption routine - MUCH faster than public/private key
     $rc4 = new Crypt_RC4();
     if (!defined('RC4_KEY')) {
         bfLog::log('NO RC4_KEY FOUND!!');
         die('No Encryption Key');
     }
     // Use the one time encryption key the requester provided
     $rc4->setKey(RC4_KEY);
     // encrypt the data
     $encrypted = $rc4->encrypt($msg);
     // return the data, encoded just in case
     $str = base64_encode($encrypted);
     bfLog::log('Finished Encryption.... took ' . (time() - $start) . ' seconds');
     return $str;
 }
Пример #9
0
 /**
  * Purges the Joomla! update cache. We ARE NOT using this cache, but the CMS
  * does. We want to bust the cache to provent Joomla! from reporting updates
  * after we install an update through our component
  *
  * @return  bool  True on success
  */
 public function purgeJoomlaUpdateCache()
 {
     bfLog::log('running purgeJoomlaUpdateCache');
     $db = JFactory::getDbo();
     // Modify the database record
     $update_site = new stdClass();
     $update_site->last_check_timestamp = 0;
     $update_site->enabled = 1;
     $update_site->update_site_id = 1;
     $db->updateObject('#__update_sites', $update_site, 'update_site_id');
     $query = $db->getQuery(TRUE)->delete($db->quoteName('#__updates'))->where($db->quoteName('update_site_id') . ' = ' . $db->quote('1'));
     $db->setQuery($query);
     if (method_exists($db, 'execute')) {
         if ($db->execute()) {
             return TRUE;
         } else {
             return FALSE;
         }
     } else {
         if ($db->query()) {
             return TRUE;
         } else {
             return FALSE;
         }
     }
 }