Jump to content

scootstah

Staff Alumni
  • Posts

    3,858
  • Joined

  • Last visited

  • Days Won

    29

Posts posted by scootstah

  1. Let's do a real comparison:

     

    Option 1: Permitting arbitrary file extensions and arbitrary file content

    An attacker can upload a file named “evil.php” and execute embedded code.

     

    Option 2: Permitting arbitrary file extensions and performing server-side MIME sniffing

    An attacker can upload a file named “evil.php” and execute embedded code.

     

    Option 3: Enforcing an image file extension and permitting arbitrary file content (my approach)

    An attacker can only upload files like “evil.png” and not execute any embedded code.

     

    Option 4: Enforcing an image file extension and performing server-side MIME sniffing (your approach)

    An attacker can only upload files like “evil.png” and not execute any embedded code.

     

    As you can see: The MIME sniffing has absolutely no effect. It's about the other factors (namely the file extension).

    Okay, I see what you're saying now. I can agree with that.

     

    And, no, embedding code in an image structure is not difficult at all.

    No, difficult part is figuring out how to execute it. You can embed PHP in an image all day long, but unless you find a vulnerability within the application that treats the image like PHP, nothing will come of it.

  2. Are you sure that json is correct - gives my a syntax error when attempting to decode?

    It's truncated. This is valid:

    {
        "meta": {
            "code": 200,
            "requestId": "561d5921498ed5a1feee2f41"
        },
        "response": {
            "venues": [
                {
                    "id": "516094748302afa746c58951",
                    "name": "Five Guys",
                    "contact": {
                        "phone": "+442072402057",
                        "formattedPhone": "+44 20 7240 2057",
                        "twitter": "five_guys",
                        "facebook": "19836964440",
                        "facebookUsername": "fiveguys",
                        "facebookName": "Five Guys"
                    },
                    "location": {
                        "address": "1-3 Long Acre",
                        "crossStreet": "at Cranbourne St",
                        "lat": 51.51177397755055,
                        "lng": -0.12685775756835938,
                        "postalCode": "WC2E 9LH",
                        "cc": "GB",
                        "city": "Covent Garden",
                        "state": "Greater London",
                        "country": "United Kingdom",
                        "formattedAddress": [
                            "1-3 Long Acre (at Cranbourne St)",
                            "Covent Garden",
                            "Greater London",
                            "WC2E 9LH",
                            "United Kingdom"
                        ]
                    },
                    "categories": [
                        {
                            "id": "4bf58dd8d48988d16c941735",
                            "name": "Burger Joint",
                            "pluralName": "Burger Joints",
                            "shortName": "Burgers",
                            "icon": {
                                "prefix": "https:\/\/ss3.4sqi.net\/img\/categories_v2\/food\/burger_",
                                "suffix": ".png"
                            },
                            "primary": true
                        }
                    ],
                    "verified": true,
                    "stats": {
                        "checkinsCount": 14621,
                        "usersCount": 9895,
                        "tipCount": 348
                    },
                    "url": "http:\/\/www.fiveguys.co.uk",
                    "allowMenuUrlEdit": true,
                    "specials": {
                        "count": 0,
                        "items": [
                            
                        ]
                    },
                    "hereNow": {
                        "count": 3,
                        "summary": "3 people are here",
                        "groups": [
                            {
                                "type": "others",
                                "name": "Other people here",
                                "count": 3,
                                "items": [
                                    
                                ]
                            }
                        ]
                    },
                    "storeId": "",
                    "referralId": "v-1444763937"
                },
                {
                    "id": "4cf9619bee9cb60c7bc883ad",
                    "name": "Hakkasan",
                    "contact": {
                        "phone": "+442079277000",
                        "formattedPhone": "+44 20 7927 7000",
                        "twitter": "hakkasanmayfair"
                    },
                    "location": {
                        "address": "17 Bruton St",
                        "lat": 51.5104785955435,
                        "lng": -0.14460325241088867,
                        "postalCode": "W1J 6QB",
                        "cc": "GB",
                        "city": "Mayfair",
                        "state": "Greater London",
                        "country": "United Kingdom",
                        "formattedAddress": [
                            "17 Bruton St",
                            "Mayfair",
                            "Greater London",
                            "W1J 6QB",
                            "United Kingdom"
                        ]
                    },
                    "categories": [
                        {
                            "id": "4bf58dd8d48988d142941735",
                            "name": "Asian Restaurant",
                            "pluralName": "Asian Restaurants",
                            "shortName": "Asian",
                            "icon": {
                                "prefix": "https:\/\/ss3.4sqi.net\/img\/categories_v2\/food\/asian_",
                                "suffix": ".png"
                            },
                            "primary": true
                        }
                    ],
                    "verified": false,
                    "stats": {
                        "checkinsCount": 7417,
                        "usersCount": 5145,
                        "tipCount": 255
                    },
                    "url": "http:\/\/hakkasan.com\/mayfair",
                    "allowMenuUrlEdit": true,
                    "specials": {
                        "count": 0,
                        "items": [
                            
                        ]
                    },
                    "hereNow": {
                        "count": 2,
                        "summary": "2 people are here",
                        "groups": [
                            {
                                "type": "others",
                                "name": "Other people here",
                                "count": 2,
                                "items": [
                                    
                                ]
                            }
                        ]
                    },
                    "referralId": "v-1444763937"
                },
                {
                    "id": "50509c8be4b0b28cb0bd0785",
                    "name": "Mezzah Lounge",
                    "contact": {
                        "phone": "+442077301234",
                        "formattedPhone": "+44 20 7730 1234",
                        "twitter": "harrods"
                    },
                    "location": {
                        "address": "87\u2013135 Brompton Rd",
                        "crossStreet": "Fourth Floor, Harrods",
                        "lat": 51.49864750188004,
                        "lng": -0.1628856295752017,
                        "postalCode": "SW1X 7XL",
                        "cc": "GB",
                        "city": "Greater London",
                        "state": "Greater London",
                        "country": "United Kingdom",
                        "formattedAddress": [
                            "87\u2013135 Brompton Rd (Fourth Floor, Harrods)",
                            "Greater London",
                            "Greater London",
                            "SW1X 7XL",
                            "United Kingdom"
                        ]
                    }
                }
            ]
        }
    }
    But, it's missing the response.groups part.

     

    EDIT:

    How do I do that?

    shuffle($results)

    gives error

    What error are you getting?

  3. But don't claim that getimagesize() will make the file safe for storage

    I was not intending to make that claim, so apologies if I did. The MIME check is only relevant for the process of saving the file to the server - once it's there you have to take other things into consideration. No, a MIME check cannot prevent chameleons, but it can prevent regular files that you don't want. So instead of being able to upload "evil.php" and then executing it from your browser, you'd have to embed code into the image and figure out a way to make it execute, which is a much more difficult task.

     

    It's much more important to explicitly declare the content type,

    And how would you know what content type to declare if you don't look at the MIME?

     

    And storing unfiltered data is what we do most of the time. There's no getimagesize() for text input.

    That's different. Nobody is looking at raw database data directly after saving it like you would with an uploaded avatar image or such.

  4. A lot more can be affected besides just Javascript in a web browser. Clients come in many forms.

     

    So again, the problem lies with the viewer. Since you can't be sure that a file doesn't have embedded code in it, you need to be sure that it can't be executed even if it did exist. I've tested this in the past by embedding PHP into a JPG. The file had an "image/jpeg" MIME type and could be viewed with any image viewer just like a normal JPG. But change the extension to .php and now it is a PHP file. However nothing can happen unless you treat the file like a PHP file. If you include() it, eval() it, or otherwise cause it to be parsed as PHP you'll have a problem. But if you treat it like an image, there is no problem. It doesn't matter if there is PHP embedded unless the application viewing it has a vulnerability that causes the PHP to parsed and executed.

     

    I may be wrong but I don't believe simply embedding Javascript into a valid image file is going to cause it to be executed. At least, I can't find anything that says that is the case.

     

    EDIT: Also you seem to be under the impression that your suggestions and checking MIME types are mutually exclusive. One should be implementing XSS protections regardless of whether they're handling file uploads or not - that's a given. Checking the MIME type is still important though, unless you want to be storing a bunch of .exe's and .pdf's.

  5. You'll have to run this one in your browser.

    <?php
    
    $expected = 'Hello, World!';
    $string = '';
    $charPool = range(32, 126);
    unset($charPool[2], $charPool[7]);
    $charPool = implode('', array_map(function($char){ return chr($char); }, $charPool));
    
    echo <<<HEREDOC
    <style type="text/css">#hello-world span{font-family:monospace;width:20px;height:20px;display:inline-block;text-align:center;vertical-align:middle;</style><div id="hello-world"></div><script type="text/javascript">for(var el=document.getElementById("hello-world"),expected="Hello, World!",pool='{$charPool}',i=0;i<expected.length;i++){var newEl=document.createElement("span");el.appendChild(newEl),el.children[i].interval=setInterval(function(e){var l=Math.floor(Math.random()*(pool.length+1));el.children[e].textContent=pool[l],el.children[e].textContent==expected[e]&&clearInterval(el.children[e].interval)},50,i)}</script>
    HEREDOC;
    
    ?>
    
    Nobody said we can't use Javascript, right? :)
  6. Yeah, let's remove all this silly HTML-escaping from our applications, because if the user executes embedded code, that's definitely their fault. That's not our department.

    Let me know when my web browser can natively execute malicious PHP code embedded in a file. Considering you haven't brought any alternative to MIME types to the table, what exactly are you saying here? That MIME types are meaningless, file extensions are meaningless, and we simply store whatever file the client gives us? Okay...

     

    It. doesn't. matter.

     

    Use the filename, use your beloved MIME heuristics, flip a coin, it doesn't matter.

    How does it not matter? You just blindly save every file that a user gives you, or what?

  7. <?php

    $string = '';

    $expected = 'Hello, World!';

    $biggestChar = 0;

    for ($i = 0; $i < strlen($expected); $i++) {
    $biggestChar = max($biggestChar, ord($expected[$i]));
    }

    while ($string != $expected) {
    $string = '';

    for ($i = 0; $i < strlen($expected); $i++) {
    $char = mt_rand(1, $biggestChar);
    $string .= chr($char);
    }
    }

    echo $string;
    I've been running this for about 30 minutes now with $expected = 'Hello' and it hasn't finished yet.
  8. Is a PHP script an image if only it starts with a PNG signature?

    Yes, by definition.

     

    The question is: How does it get interpreted?

    Well, that's the important part. As long as you treat an image like an image, then it doesn't matter if there is embedded code. At that point it falls to the viewer to safely handle the image and lot allow arbitrary code to execute.

     

    I'm not against MIME heuristics. They can catch obvious user errors, and they may increase security a tiny bit. But that's really just a bonus feature. All other measures I've mentioned are much, much more important.

    So how do you tell the client their file is not of an allowed type? How do you decide which file extension to give the uploaded file? How do you decide which content header to send when you display a file?

  9. Many webservers only check the extension, so a file called “foo.php” will in fact be treated as a PHP script, even if its structure happens to resemble an image.

    Correct, which is why you save it to the filesystem with the correct corresponding extension, and not the one that the client supplied.

     

    It sounds like you're saying checking the MIME type is pointless. How else would you determine whether a file is an image or something else?

  10. You can't do that. All of the PHP is executed before the JS even exists. You can't loop or re-call PHP from JS. You'd have to use an AJAX request.

     

    But what you're doing is crazy inefficient. To create a live chat you want to be using WebSockets, which create a persistent TCP connection between client and server. It is easily possible to achieve the alert with WebSockets because it is possible for all clients to know exactly when a message was pushed.

  11. getimagesize() will return false if the given argument is not an image. It checks the MIME type. Yes, the file could contain malicious code even if it is also a valid image. But such a file is generally still safe to store and use, and the only problem would come from a vulnerability in the viewer.

     

    Checking the MIME type is the best that you can do.

  12. Just for giggles:

    $fun = array(
     'First Word' => 'Programming',
     'Second Word' => 'in',
     'Third Word' => 'PHP',
     'Fourth Word' => 'is',
     'Fifth Word' => 'fun!',
     'Programming in PHP is fun!'
    );
    
    foreach($fun as $key => $val) 
    {
        if ($val != end(array_values($fun))) {
            echo "$key, ";
        }
    
        echo "$val<br />";
    }
  13. You happily accept multiple extensions as long as the last extension is an image extension. So anybody can upload a file named “malicious.php.jpg” with embedded PHP code, and chances are your webserver will actually execute it.

    They're only using the extension to check if it's one of the allowed image types. But, this will prevent non-image uploads:

    $check = getimagesize($_FILES["image"]["tmp_name"]);
    if($check !== false) {
    There's a still the problem that the extension is meaningless for what they're trying to achieve, but at least the uploaded file will be an image.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.