Published: April 20, 2015
Last updated:

How to apply SUPEE-5344 and SUPEE-1533 without SSH

Recently released announce regarding Magento vulnerability disclosed by CheckPoint urges Magento patches SUPEE-1533 and SUPEE-5344 installation. The patches are available for download at MagentoCommerce site: https://www.magentocommerce.com/products/downloads/magento/ To test if your store is vulnerable use our Scan your store button in sidebar. The only problem with these patches is SSH requirement, which some hosts do not provide. If you have SSH access, you can install patches as shown in How to apply SUPEE-5344 and SUPEE-1533 via SSH. It is still possible to apply these patches even without SSH via FTP/sFTP or direct execution via PHP as shown below in this article. If you wish to save time and have us to install these patches for you, simply click here to order installation. If you have any difficulties with applying the patches please let us know in comments, so we can find the solution together.

Note: Before patching make sure to Disable Magento Compiler if you use it at System > Configuration > Tools > Compilation and clear compiled cache.

Applying Magento patches via FTP/sFTP or FileManager

To apply patches via FTP we simply replace changed files. This way can not be used blindly if you or your developers have changed any core Magento files (which is a big no-no, by the way). Such changes should be re-applied to patched files, or you loose these changes. Patch SUPEE-1533 (Magento 1.7.x.x-1.9.1.0) applied to the following files:
  • app/code/core/Mage/Adminhtml/Block/Dashboard/Graph.php
  • app/code/core/Mage/Adminhtml/controllers/DashboardController.php
Patched version of files for Magento 1.7.0.0-1.9.1.0 (including 1.7.0.2, 1.8.1.0 and 1.9.1.0 versions) packed into single ZIP archive: SUPEE-1533.zip. Simply unpack it and replace files on your store by uploading app folder into your Magento root directory. Patch SUPEE-5344 (Magento 1.8.x.x-1.9.1.0) applied to the following files:
  • app/code/core/Mage/Admin/Model/Observer.php
  • app/code/core/Mage/Core/Controller/Request/Http.php
  • app/code/core/Mage/Oauth/controllers/Adminhtml/Oauth/AuthorizeController.php
  • app/code/core/Mage/XmlConnect/Model/Observer.php
  • lib/Varien/Db/Adapter/Pdo/Mysql.php
Patched version of these files for Magento 1.8.x.x-1.9.1.0 packed into single ZIP archive: SUPEE-5344.zip. Simply unpack it and replace files on your store by uploading app/ and lib/ folders into your Magento root.  

Patches for other versions (1.7.0.2 and earlier)

Older versions are patched in the same way, I have combined downloads for all versions into a single table. The last column contains combined version of both patches to upload both patches at once.
Magento versionSUPEE-5344SUPEE-1533COMBINED (both patches at once)
Magento 1.8.0.0-1.9.1.0SUPEE-5344.zipSUPEE-1533.zipSUPEE-1533-5344.zip
Magento 1.7.0.0-1.7.0.2SUPEE-5344-1.7.zipSUPEE-1533.zipSUPEE-1533-5344-1.7.zip
Magento 1.6.1.0-1.6.2.0SUPEE-5344-1.6.zipSUPEE-1533-1.6.zipSUPEE-1533-5344-1.6.1.zip
Magento 1.6.0.0
not prepared (due to low volume)
use official .sh patch file or upgrade to nearest 1.6.2.0
Magento 1.5.1.0SUPEE-5344-1.5.1.zipSUPEE-1533-1.5.1.zipSUPEE-1533-5344-1.5.1.zip
Magento 1.4.0.0-1.5.0.1
not prepared (due to high customization rate and overrides possibility)
use official .sh patch file
Magento 1.3
not prepared (due to high customization rate and overrides possibility)
use patch from here
Simply unpack the archive and replace files on your store by uploading app/ and lib/ folders into your Magento root directory. If you use PHP opcode caches (APC/XCache/eAccelerator) make sure to flush it after patching, otherwise code will continue to run from caches.

Verification

Verify that your store have green SAFE status at http://magento.com/security-patch and our patch tester page. Additionally, if your store still using default /admin/ path, you may consider securing your Magento /admin/ by admin path change. Done.
Update: Make sure also to apply the latest SUPEE-5994 and SUPEE-6285.
As there is an exploit in the wild, if your store was not yet patched to the date, the chances are that it is exploited already. Make sure to check list of admin users. You can do it System > Permissions > Users and System > Permissions > Roles in Backend. Make sure to delete any unknown users, especially with emails in example.com domain. Refer to Recovery after Shoplift vulnerability article for detailed list of actions.

Applying Magento patches via PHP

Upload one of PHP shells to your Magento root subfolder. Sample PHP shells are PHP Shell and phpFileManager. Just upload one of shells to your Magento site, open the shell in browser and run Magento patches in the shell provided just like via SSH.  

Applying patches manually (by merging patches with your changes in core files)

Use this way only if you or your developers have changed core Magento files that need to be patched. Apply the changes from the diffs below line by line editing all files. Lines prefixed with a “+” (plus sign) should be added, lines prefixed with “-” (minus sign) should be removed, “@@” characters indicate position (line number and column). Complete DIFF for SUPEE-1533 (Magento 1.7.0.0-1.9.1.0):
diff --git app/code/core/Mage/Adminhtml/Block/Dashboard/Graph.php app/code/core/Mage/Adminhtml/Block/Dashboard/Graph.php
index c698108..6e256bb 100644
--- app/code/core/Mage/Adminhtml/Block/Dashboard/Graph.php
+++ app/code/core/Mage/Adminhtml/Block/Dashboard/Graph.php
@@ -444,7 +444,7 @@ class Mage_Adminhtml_Block_Dashboard_Graph extends Mage_Adminhtml_Block_Dashboar
             }
             return self::API_URL . '?' . implode('&', $p);
         } else {
-            $gaData = urlencode(base64_encode(serialize($params)));
+            $gaData = urlencode(base64_encode(json_encode($params)));
             $gaHash = Mage::helper('adminhtml/dashboard_data')->getChartDataHash($gaData);
             $params = array('ga' => $gaData, 'h' => $gaHash);
             return $this->getUrl('*/*/tunnel', array('_query' => $params));
diff --git app/code/core/Mage/Adminhtml/controllers/DashboardController.php app/code/core/Mage/Adminhtml/controllers/DashboardController.php
index eebb471..f9cb8d2 100644
--- app/code/core/Mage/Adminhtml/controllers/DashboardController.php
+++ app/code/core/Mage/Adminhtml/controllers/DashboardController.php
@@ -92,7 +92,8 @@ class Mage_Adminhtml_DashboardController extends Mage_Adminhtml_Controller_Actio
         if ($gaData && $gaHash) {
             $newHash = Mage::helper('adminhtml/dashboard_data')->getChartDataHash($gaData);
             if ($newHash == $gaHash) {
-                if ($params = unserialize(base64_decode(urldecode($gaData)))) {
+                $params = json_decode(base64_decode(urldecode($gaData)), true);
+                if ($params) {
                     $response = $httpClient->setUri(Mage_Adminhtml_Block_Dashboard_Graph::API_URL)
                             ->setParameterGet($params)
                             ->setConfig(array('timeout' => 5))

  Complete DIFF for SUPEE-5344 (Magento 1.8.0.0-1.9.1.0):
diff --git app/code/core/Mage/Admin/Model/Observer.php app/code/core/Mage/Admin/Model/Observer.php
index bd00181..6a5281c 100644
--- app/code/core/Mage/Admin/Model/Observer.php
+++ app/code/core/Mage/Admin/Model/Observer.php
@@ -44,6 +44,10 @@ class Mage_Admin_Model_Observer
     {
         $session = Mage::getSingleton('admin/session');
         /** @var $session Mage_Admin_Model_Session */
+
+        /**
+         * @var $request Mage_Core_Controller_Request_Http
+         */
         $request = Mage::app()->getRequest();
         $user = $session->getUser();

@@ -58,7 +62,7 @@ class Mage_Admin_Model_Observer
         if (in_array($requestedActionName, $openActions)) {
             $request->setDispatched(true);
         } else {
-            if($user) {
+            if ($user) {
                 $user->reload();
             }
             if (!$user || !$user->getId()) {
@@ -69,13 +73,14 @@ class Mage_Admin_Model_Observer
                     $session->login($username, $password, $request);
                     $request->setPost('login', null);
                 }
-                if (!$request->getParam('forwarded')) {
+                if (!$request->getInternallyForwarded()) {
+                    $request->setInternallyForwarded();
                     if ($request->getParam('isIframe')) {
                         $request->setParam('forwarded', true)
                             ->setControllerName('index')
                             ->setActionName('deniedIframe')
                             ->setDispatched(false);
-                    } elseif($request->getParam('isAjax')) {
+                    } elseif ($request->getParam('isAjax')) {
                         $request->setParam('forwarded', true)
                             ->setControllerName('index')
                             ->setActionName('deniedJson')
diff --git app/code/core/Mage/Core/Controller/Request/Http.php app/code/core/Mage/Core/Controller/Request/Http.php
index 6513db9..31eb6d6 100644
--- app/code/core/Mage/Core/Controller/Request/Http.php
+++ app/code/core/Mage/Core/Controller/Request/Http.php
@@ -76,6 +76,13 @@ class Mage_Core_Controller_Request_Http extends Zend_Controller_Request_Http
     protected $_beforeForwardInfo = array();

     /**
+     * Flag for recognizing if request internally forwarded
+     *
+     * @var bool
+     */
+    protected $_internallyForwarded = false;
+
+    /**
      * Returns ORIGINAL_PATH_INFO.
      * This value is calculated instead of reading PATH_INFO
      * directly from $_SERVER due to cross-platform differences.
@@ -534,4 +541,26 @@ class Mage_Core_Controller_Request_Http extends Zend_Controller_Request_Http
         }
         return false;
     }
+
+    /**
+     * Define that request was forwarded internally
+     *
+     * @param boolean $flag
+     * @return Mage_Core_Controller_Request_Http
+     */
+    public function setInternallyForwarded($flag = true)
+    {
+        $this->_internallyForwarded = (bool)$flag;
+        return $this;
+    }
+
+    /**
+     * Checks if request was forwarded internally
+     *
+     * @return bool
+     */
+    public function getInternallyForwarded()
+    {
+        return $this->_internallyForwarded;
+    }
 }
diff --git app/code/core/Mage/Oauth/controllers/Adminhtml/Oauth/AuthorizeController.php app/code/core/Mage/Oauth/controllers/Adminhtml/Oauth/AuthorizeController.php
index c30d273..36542f9 100644
--- app/code/core/Mage/Oauth/controllers/Adminhtml/Oauth/AuthorizeController.php
+++ app/code/core/Mage/Oauth/controllers/Adminhtml/Oauth/AuthorizeController.php
@@ -55,7 +55,7 @@ class Mage_Oauth_Adminhtml_Oauth_AuthorizeController extends Mage_Adminhtml_Cont
      */
     public function preDispatch()
     {
-        $this->getRequest()->setParam('forwarded', true);
+        Mage::app()->getRequest()->setInternallyForwarded();

         // check login data before it set null in Mage_Admin_Model_Observer::actionPreDispatchAdmin
         $loginError = $this->_checkLoginIsEmpty();
diff --git app/code/core/Mage/XmlConnect/Model/Observer.php app/code/core/Mage/XmlConnect/Model/Observer.php
index e6cb947..36142ac 100644
--- app/code/core/Mage/XmlConnect/Model/Observer.php
+++ app/code/core/Mage/XmlConnect/Model/Observer.php
@@ -143,7 +143,7 @@ class Mage_XmlConnect_Model_Observer
         /** @var $request Mage_Core_Controller_Request_Http */
         $request = Mage::app()->getRequest();
         if (true === $this->_checkAdminController($request, $event->getControllerAction())) {
-            $request->setParam('forwarded', true)->setDispatched(true);
+            $request->setInternallyForwarded()->setDispatched(true);
         }
     }

@@ -160,7 +160,7 @@ class Mage_XmlConnect_Model_Observer
         if (false === $this->_checkAdminController($request, $event->getControllerAction())
             && !Mage::getSingleton('admin/session')->isLoggedIn()
         ) {
-            $request->setParam('forwarded', true)->setRouteName('adminhtml')->setControllerName('connect_user')
+            $request->setInternallyForwarded()->setRouteName('adminhtml')->setControllerName('connect_user')
                 ->setActionName('loginform')->setDispatched(false);
         }
     }
diff --git lib/Varien/Db/Adapter/Pdo/Mysql.php lib/Varien/Db/Adapter/Pdo/Mysql.php
index 2226331..d1c6942 100644
--- lib/Varien/Db/Adapter/Pdo/Mysql.php
+++ lib/Varien/Db/Adapter/Pdo/Mysql.php
@@ -2834,10 +2834,6 @@ class Varien_Db_Adapter_Pdo_Mysql extends Zend_Db_Adapter_Pdo_Mysql implements V

         $query = '';
         if (is_array($condition)) {
-            if (isset($condition['field_expr'])) {
-                $fieldName = str_replace('#?', $this->quoteIdentifier($fieldName), $condition['field_expr']);
-                unset($condition['field_expr']);
-            }
             $key = key(array_intersect_key($condition, $conditionKeyMap));

             if (isset($condition['from']) || isset($condition['to'])) {

If you have any difficulties with applying the patches please let us know in comments, so we can find the solution together.

Posted in: Magento Maintenance

97 votes, 4.62 avg. rating (92% score)