Magento Integer based SQL injection vulnerability in product parameter

Recently I was asked to look into a potential PCI compliance issue in Magento 1.7/1.8/1.9. The potential issue was uncovered by ControlScan. The summary was as follows:

Integer based SQL injection vulnerability in product parameter to /checkout/cart/add/uenc/<snip>,/product/<id>/
 
Risk: High (3)
Port: 80/tcp
Protocol: tcp
Threat ID: web_prog_sql_integer

Upon diving into the additional supplied information, it was almost immediately clear what the test was doing. It was performing a POST request against the URL: /checkout/cart/add/uenc/<snip>,/product/XYZ/
XYZ translates to a valid Magento product id. In the payload (POST’d multipart/form-data) that would get parsed into the PHP $_POST superglobal, an initial request passed product=XYZ, and a subsequent request passed product=XYZ-2.

The scan saw the same output returned for each request, and thus assumed the cart might be getting “duped” by the invalid XYZ-2.

Let’s take a look at the code which handles this submission (which is an AJAX style action that adds a product to the cart). It is located in app/code/core/Mage/Checkout/controllers/CartController.php, starting around line 170, in the addAction public method. The take-away here is the $params variable setup in addAction, as well as the product id discovery in _initProduct both retrieve their data by calling $this->getRequest()->getParams(); — this parameter data comes from any number of places, including the URL, GET, or POST. In this instance, the product variable is being parsed out of the URL, and the product supplied via POST is never referenced. No wonder the output was the same, the URL was the same in both cases, the modified POST data was never a factor.

If you simply want to tighten up your cart to get it to pass your PCI compliance scan, the following code will do that for you, just replace the top part of addAction with the following, and be prepared for an eventual upgrade to undo this patch.

public function addAction()
{
    $cart   = $this->_getCart();
    $params = $this->getRequest()->getParams();

    $postInput = file_get_contents("php://input");
    $postStrDataArr = explode("\n", $postInput);
    $postStrData = array_pop($postStrDataArr);
    parse_str($postStrData, $postData);

        if ((isset($postData['product']) && $postData['product'] != $params['product']) || !is_numeric($params['product']))
        throw new Exception('Invalid Product ID');

    try {

This modification compares the parameter parsed via the URL with the parameter passed via POST and throws an Exception if the two do not match.

No doubt there is a better and more Magento-esque way to remedy this issue, but the above will work in a pinch.

PHP/AJAX file upload with progress bar, part 3

Part 1, Part 2

I pulled this back out over the weekend and did a little work on it. The backend code is now totally functional, however I would consider it to be alpha quality. It just needs to be wrapped in a UI now, check it out and let me know what you think. Try the demo with JavaScript enabled first, once the upload completes you will see the result is a mash-up that looks like PHP’s $_REQUEST/$_FILES. Hit the resulting url again within 60 seconds and you will see the status side of things (Using a GET request, you don’t want to re-post the form data). Total bytes, bytes received, percent complete. Try it again with JavaScript disabled and behold the standard php handler.

Source
Demo

XSLT shorthand for PHP

As I trudge toward Exhibition v2, I am taking the templating in an entirely new direction. Exhibition deals with XML, a lot of XML. As a direct consequence there is a fairly substantial amount of XSLT. Noticing that XSLT has a very straightforward syntax, I decided to write a little preprocessor to save my fingers some walking later on. Most commands boil down to “command” or “command required_argument” (required_argument usually being an XPath expression). So, that’s exactly what I pruned it down to.

<@ for-each atom @>

versus

<xsl:for-each select=”atom”>

Check it out —

xsltemplate.phps

xsltemplate-test.tpl
xsltemplate-test.xml
xsltemplate-test.xsl
(examples stolen from W3Schools)

PHP/AJAX file upload with progress bar, part 2

I made some good progress on implementing the server side of things as outlined in my prior post on this subject, but I got lazy as usual. I simply haven’t gotten around to finishing this up, so I decided to throw the code up and make a post about it in the hopes that someone will either badger me into completing it, or find some of what is already there useful. The code as of now implements what could be a reasonably useful (python asyn* inspired) set of utility classes for writing socket applications in PHP. Not that anyone would ever want to do anything like that, of course.

http://evilprojects.com/hacks/

PHP: Protecting your code (Zend Encoder/IonCube/SourceCop)

SourceCop Decoder

Personally, I have never found need to encode/encrypt/obfuscate any PHP. I do however know that there is a large audience of developers and/or organizations out there that do rely on such obfuscation to protect their works. Not being sure if it has hit the news or not, as I have been too busy of late to even open up my RSS aggregator to skim the headlines, know that there is at least one service in the wild that can successfully decode Zend Encoder and IonCube encoded files. It’s not perfect by any means, as it is reconstructing the code based on the opcodes, but it does return it in a format that is true to the original as far as execution and reasonably easy for a human to parse.

I wrote this little number the other day after running across a script I was wanting to use, in which one component was obviously dependant upon register_globals. My gosh, if I only had the code I could fix that! Fortunately it was obfuscated with an application called SourceCop, which provides very little in the way of protection. Come on guys, you could at least obfuscate the code itself first, munging whitespace, variable and function names. As it was, it took a mere 20 minutes to write a script that would replace an encoded file with a pristine copy of the original. At any rate, here is the script, do note that it was a quick hack and as such it may or may not work for you. It will also simply overwrite any SourceCop encoded files fed to it, so you will want to create a backup first, you have been warned.
Update: 2/23/2006, revised script

PHP/AJAX file upload with progress bar

Over the past couple of days I have been pondering adding some file upload functionality to the form classes I have been using for a bit over a year now. History repeats itself, again, time spent pondering instead of just getting on with the nitty gritty means I start thinking about ideal functionality. So, as I pondered how to go about sanely handling file uploads features started coming to mind, and one of them just wouldn’t go away. A semi-realtime inline file upload progress indicator. Well, that doesn’t sound so hard.

I spent some time with Google doing the requisite research to find that there are a number of stumbling blocks. The first being client-side, when a browser window/frame is busy pushing a file or files up the pipe, it seems that it is just that, busy. Which makes it a bit difficult to talk it into displaying updates. This seems to be pretty easily solved by pushing the file upload through a hidden iframe referenced by the target attribute on the form.

That certainly isn’t where the problems end. As luck would have it, not only is the browser happy to be working against us, so is PHP, in more ways than one.

When the execution unit handling the upload gets hit with the POST, it would seem that it likes to make itself busy as well. Ok, so no way to get the status of the file upload from the thread/process actually handling the upload. Apparently there are some patches against PHP to rectify this situation, but until they get committed and see a release they are unusable for most people. I am all for gratuitously hacking my own PHP install, but it seemed like there must be a better way.

I then stumbled across another method. Scan the upload_tmp_dir (PHP INI variable) for files of a known naming scheme, looking for the one with the latest timestamp. The current size of this file could be pushed back to the browser so that it could calculate the upload progress. This method is also not without its glaring faults. The probability of a race condition is too high for any kind of production use. Oh wait, scratch that, I’m starting to sound like a PHP developer, let me rephrase… There is an unavoidable possibility of a race condition, so this method cannot be used. Well… Wait a minute, there is an upload_tmp_dir variable. Why don’t we just generate some kind of unique form id to be passed back to us when we get the POST, then it should be possible to create a directory to have PHP put the file(s) in of a known name, eliminating our race, no? I suppose upload_tmp_dir being read-only is a bit of a stumbling block with that idea, considering we already decided hacks to the PHP source were out. Not to mention PHP probably isn’t going to let us set the variable before it gets busy processing that form data anyway.

Google led me to a couple more resources for accomplishing this throughout the course of my research, but they all involved an external non-PHP script to handle the upload and drop status information somewhere accessible. Unacceptable I say! There must be a way to do it with PHP alone!

I have theorized a method, implementation forthcoming. Here is a brief summary. Have an onSubmit handler frob a PHP script and retrieve a URL to apply to the action property of the form, said PHP script will have just launched a PHP-based very simple webserver. This webserver’s sole purpose in life is to eat POST’s and parse multipart form data. This same PHP script will update an accessible location with the status of the upload. The hidden iframe trick gets used to free up the window with the form in it. This window can now pull upload status via XMLHttpRequest and update a progress bar accordingly. This method also has the benefit of being able to degrade gracefully in the event that JavaScript is unavailable on the client. The default action URL can be implemented as a standard file upload handler.