WebGoat
WebGoat是一个基于java应用的开源漏洞环境
安装
要确保虚拟机中装有Java环境
下载webgoat-server/webwolf文件
在虚拟机中执行以下命令
java -jar webgoat-server文件名 --server.address=0.0.0.0 java -jar webwolf文件名 --server.address=0.0.0.0
Web页面测试是否安装成功,访问http://本机ip:8080/WebGoat,出现以下页面则表明安装成功
1 认证机制
攻击方式
- 通过html隐藏的input标签值
- 通过移除/修改提交的参数来确认程序的响应
- 通过猜测或暴力破解强制访问站点的某些url
1.1 绕过认证(Authentication Bypasses)
1.1.1 实践
修改上述http消息主体的参数为secQuestion2/3
成功绕过该验证机制
1.1.2 源代码
public boolean verifyAccount(Integer userId, HashMap<String, String> submittedQuestions) {
//short circuit if no questions are submitted
if (submittedQuestions.entrySet().size() != secQuestionStore.get(verifyUserId).size()) {
return false;
}
if (submittedQuestions.containsKey("secQuestion0") && !submittedQuestions.get("secQuestion0").equals(secQuestionStore.get(verifyUserId).get("secQuestion0"))) {
return false;
}
if (submittedQuestions.containsKey("secQuestion1") && !submittedQuestions.get("secQuestion1").equals(secQuestionStore.get(verifyUserId).get("secQuestion1"))) {
return false;
}
// else
return true;
}
}
由上述代码可知,身份认证中只对变量名为secQuestion0/1的变量进行了检验,安全设置只局限在secQuestion0/1变量上,如果修改变量名为secQuestion3/4,就可以绕过该限制,从而成功实施攻击。该漏洞代码的缺陷:
- 没有对传入的变量进行限制
1.2 JWT
1.2.1 概述
JWT(Json Web Tokens),JWT与Web服务器交互
在此流程中,可以看到用户使用用户名和密码登录服务器后返回的成功身份验证。服务器创建一个新令牌并将其返回给客户端。当客户端对服务器进行连续调用时,它将新令牌附加在“授权”标头中。服务器读取令牌,并在成功验证后首先验证签名,然后服务器使用令牌中的信息来识别用户。
JWT签名
每个JWT令牌至少应在发送给客户端之前进行签名,如果未签名,则客户端应用程序将能够更改令牌的内容。
1.2.2 token的组成
令牌是base64-url编码的,由三部分组成:header.claims.signature
JWT的内容以Base64URL进行了编码,base64加解码网站:https://jwt.io/#encoded-jwt
header头部
以上图中的JWT为例,头部解码后为:
{
"alg":"HS256",
"typ":"JWT"
}
- alg:是说明这个JWT的签名使用的算法的参数,常见值用HS256(默认),HS512等,也可以为None。HS256表示HMAC SHA256。
- typ:说明这个token的类型为JWT
claims声明
上图JWT的claims解码后为:
{
"exp": 1416471934,
"user_name": "user",
"scope": [
"read",
"write"
],
"authorities": [
"ROLE_ADMIN",
"ROLE_USER"
],
"jti": "9bc92a44-0b1a-4c5e-be70-da52075b9a84",
"client_id": "my-client-with-secret"
}
其中有些字段是JWT的固定参数,有特定的含义;而另一些是服务器自定义的参数,用来表示通话信息等。
signature签名
服务器有一个不会发送给客户端的密码(secret),用头部中指定的算法对header和claims的内容用此密码进行加密,生成的字符串就是JWT的签名。
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
your-256-bit-secret
)
注:在HTTP传输过程中,Base64编码中的”=”,”+”,”/“等特殊符号通过URL解码通常容易产生歧义,因此产生了与URL兼容的Base64 URL编码。在Base64 URL编码中,”+”会变成”-“,”/“会变成”_”,”=”会被去掉,以此达到url safe的目的。
1.2.3 实践4
尝试更改收到的令牌并通过更改令牌成为管理员用户,一旦成为管理员,就重置投票
先切换用户,然后点击重置密码,并使用BP进行抓包:
对上述token进行解码:
此处我们将admin字段修改为true,一旦内容改变,token的签名也随之改变,所以此处我们可以将alg设为none,即没有加密算法来进行绕过。
头部
{
"alg":"none"
}
编码后:
ewogICAiYWxnIjoibm9uZSIKfQ==
声明
{
"iat": 1596437866,
"admin": "true",
"user": "Tom"
}
编码后:
ewogICJpYXQiOiAxNTk2NDM3ODY2LAogICJhZG1pbiI6ICJ0cnVlIiwKICAidXNlciI6ICJUb20iCn0=
最终token
ewogICAiYWxnIjoibm9uZSIKfQ.ewogICJpYXQiOiAxNTk2NDM3ODY2LAogICJhZG1pbiI6ICJ0cnVlIiwKICAidXNlciI6ICJUb20iCn0.
注:要把末尾的=去掉,一定要加上.
转发之后,服务器返回的响应如下:
此时我们就可以利用管理员token冒充管理员执行操作
源代码解析
从http请求中解析token的代码如下:
encodedHeader = TextCodec.BASE64URL.encode(jsonHeader);
encodedPayload = TextCodec.BASE64URL.encode(jsonPayload);
if (jsonHeader.toLowerCase().contains("none")) {
encodedSignature="";
} else {
encodedSignature = TextCodec.BASE64URL.encode(getJWTSignature(jsonHeader, encodedHeader, encodedPayload, jsonSecret));
}
从上述代码中可知,如果头部指定的算法字段为none,则签名可以为空,此代码就给篡改token有机可趁。
1.2.4 实践7
让他人代付
查看题目给出的token日志:
对token进行解码:
其中claims中的exp字段是token过期时间,将鼠标放上去JWT会自动解析时间,我们只需直接在上面修改数字查看时间,只要时间在当前时间之后就可以。同时把头部的alg置为None:
声明
{
"iat": 1526131411,
"exp": 1629217911,
"admin": "false",
"user": "Tom"
}
编码后:
ewogICJpYXQiOiAxNTI2MTMxNDExLAogICJleHAiOiAxNjI5MjE3OTExLAogICJhZG1pbiI6ICJmYWxzZSIsCiAgInVzZXIiOiAiVG9tIgp9
最终token
ewogICAiYWxnIjoibm9uZSIKfQ.ewogICJpYXQiOiAxNTI2MTMxNDExLAogICJleHAiOiAxNjI5MjE3OTExLAogICJhZG1pbiI6ICJmYWxzZSIsCiAgInVzZXIiOiAiVG9tIgp9.
修改http请求authorization的值为token
2. 不安全的对象直接引用
直接使用用户输入去访问数据和对象会造成不安全的对象直接引用。
2.1 XXE
2.1.1 XML实体
XML(EXtensible Markup Language),可扩展标记语言,是一种用于标记电子文件,使其具有结构性的标记语言,可以用来标记数据,定义数据类型。与HTML不同:HTML被设计来显示数据,XML被设计来传输数据。XML实体定义解析XML文档时被特定内容替换的标签,通常有三种类型的实体:
- 内部实体
- 外部实体
- 参数实体
一个实体必须由DTD(Document Type Definition)创造,如下图所示
一旦上述XML文档被解析(绿框中的内容),定义的实体js就会被替换成“John Smith”。在java应用中,XML可以用于从客户端获取数据发送到服务器端。
实体
实体都以&开头,以;结束,上图中&js;就是实体
内部实体
创建内部实体的格式:
<!ENTITY {实体名} "{用来替代实体的文本}">
<!ENTITY js "This is text"
调用格式
&{实体名};
&js;
外部实体
外部实体引用的是来自外部的文件:
<?xml version="1.0"?>
<!DOCTYPE test [
<!ENTITY bbb SYSTEM "1.xml">
]>
&bbb;
外部实体中的SYSTEM表示引用系统外的文件。
2.2 XXE注入
XXE(XML External Entity,XML外部实体)攻击是一种破坏应用解析XML输入的攻击。XML输入中包含一个被易受攻击的XML解析器解析的外部实体的引用就会诱发此种攻击。
2.3 XXE攻击分类
- Classic:一个外部实体包含在本地DTD语言中
- Blind: 在响应中不会显示输出或错误
- Error: 尝试从错误信息中获取资源内容
2.4 实践
XXE-4
响应中返回file:/c的文件
XXE-7
服务器可能能够接受其他的数据格式。因此,这可能导致JSON端点容易受到XXE攻击。
源代码:
public AttackResult createNewUser(@RequestBody String commentStr, @RequestHeader("Content-Type") String contentType) throws Exception {
AttackResult attackResult = failed(this).build();
if (APPLICATION_JSON_VALUE.equals(contentType)) {
comments.parseJson(commentStr).ifPresent(c -> comments.addComment(c, true));
attackResult = failed(this).feedback("xxe.content.type.feedback.json").build();
}
if (null != contentType && contentType.contains(MediaType.APPLICATION_XML_VALUE)) {
String error = "";
try {
Comment comment = comments.parseXml(commentStr);
comments.addComment(comment, false);
if (checkSolution(comment)) {
attackResult = success(this).build();
}
} catch (Exception e) {
error = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e);
attackResult = failed(this).feedback("xxe.content.type.feedback.xml").output(error).build();
}
}
return attackResult;
}
由上可知服务器端对json/xml格式的数据都进行了解析处理,所以可以将json数据改为xml数据,进而实施xxe攻击。
3.XSS
3.1 实践
3.1.1 XSS-7
点击UpdateCart,下方显示card number,可知可能存在XSS漏洞,尝试构建payload:
<script>alert("XSS Test")</script>