CVE-2022-41958: Deserialization of Untrusted Data (CWE-502)
value: super-xray is a web vulnerability scanning tool. Versions prior to 0.7 assumed trusted input for the program config which is stored in a yaml file. An attacker with local access to the file could exploit this and compromise the program. This issue has been addressed in commit `4d0d5966` and will be included in future releases. Users are advised to upgrade. There are no known workarounds for this issue.
CWE description: The product deserializes untrusted data without sufficiently verifying that the resulting data will be valid.
CVSS v3 base score: 7.8
Published: 2022-11-25T18:15Z
Repository: https://github.com/4ra1n/super-xray
Language: Java
Files changed: CHANGELOG.MD, src/main/java/com/chaitin/xray/form/LookupConfigForm.java, src/main/java/com/chaitin/xray/form/MainForm.java, src/main/java/com/chaitin/xray/test/Main.java
Commit date: 2022-11-24 20:45:39 +0800
Commit message: yaml rce

Diff: diff --git a/CHANGELOG.MD b/CHANGELOG.MD
index c3ea3ef..58fc6ab 100644
--- a/CHANGELOG.MD
+++ b/CHANGELOG.MD
@@ -95,11 +95,11 @@ Others:
 
 该版本是第一个正式版，支持了`JDK8`的版本，当环境是`JDK8`时使用`JNA`技术访问`Native`方法，通过`Windows API`实现功能；
 当环境是`JDK9+`时，反射调用方法即可。修复了一处功能`bug`并优先加载当前目录的`config.yaml`文件，不会删除，实现了保存设置功能。
 
 另外提供了两种`exe`的下载：
-- 内置`JRE`和`xray`的`exe`可以一键启动：`super-xray-0.7-jre-exe.zip`
+- 内置`JRE`的`exe`可以一键启动：`super-xray-0.7-jre-exe.zip`
 - 调用系统`JRE`的`exe`：`super-xray-0.7-system-jre.exe`
 
 第一种不需要安装任何环境，解压后直接使用；第二种需要本地`JAVA_HOME`或环境变量有配置`Java`
 
 Bug:
diff --git a/src/main/java/com/chaitin/xray/form/LookupConfigForm.java b/src/main/java/com/chaitin/xray/form/LookupConfigForm.java
index 82858c6..0aa52e2 100644
--- a/src/main/java/com/chaitin/xray/form/LookupConfigForm.java
+++ b/src/main/java/com/chaitin/xray/form/LookupConfigForm.java
@@ -1,11 +1,13 @@
 package com.chaitin.xray.form;
 
 import com.chaitin.xray.utils.StringUtil;
 import com.intellij.uiDesigner.core.GridConstraints;
 import com.intellij.uiDesigner.core.GridLayoutManager;
+import org.yaml.snakeyaml.LoaderOptions;
 import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.SafeConstructor;
 
 import javax.swing.*;
 import java.awt.*;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
@@ -55,11 +57,11 @@ public class LookupConfigForm {
             if (!StringUtil.notEmpty(MainForm.configPath)) {
                 JOptionPane.showMessageDialog(null, "无法保存");
                 return;
             }
             try {
-                Yaml yaml = new Yaml();
+                Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
                 String newConfig = configTextArea.getText();
                 MainForm.configObj = yaml.load(newConfig);
 
                 MainForm.configStr = newConfig;
 
diff --git a/src/main/java/com/chaitin/xray/form/MainForm.java b/src/main/java/com/chaitin/xray/form/MainForm.java
index d3e7aa1..3c4a467 100644
--- a/src/main/java/com/chaitin/xray/form/MainForm.java
+++ b/src/main/java/com/chaitin/xray/form/MainForm.java
@@ -10,11 +10,13 @@ import com.formdev.flatlaf.FlatLightLaf;
 import com.intellij.uiDesigner.core.GridConstraints;
 import com.intellij.uiDesigner.core.GridLayoutManager;
 import com.intellij.uiDesigner.core.Spacer;
 import org.apache.log4j.LogManager;
 import org.apache.log4j.Logger;
+import org.yaml.snakeyaml.LoaderOptions;
 import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.SafeConstructor;
 
 import javax.swing.*;
 import javax.swing.border.TitledBorder;
 import java.awt.*;
 import java.awt.event.MouseAdapter;
@@ -222,11 +224,11 @@ public class MainForm {
                 }
             }
         }
         configTemplate = configStr;
 
-        Yaml yaml = new Yaml();
+        Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
         configObj = yaml.load(configStr);
 
         try {
             if (StringUtil.notEmpty(configPath)) {
                 Files.write(Paths.get(configPath),
@@ -682,11 +684,11 @@ public class MainForm {
             }
         });
     }
 
     public void refreshConfig() {
-        Yaml yaml = new Yaml();
+        Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
         StringWriter writer = new StringWriter();
         yaml.dump(configObj, writer);
         configStr = writer.toString();
         try {
             Files.write(Paths.get("config.yaml"),
diff --git a/src/main/java/com/chaitin/xray/test/Main.java b/src/main/java/com/chaitin/xray/test/Main.java
index f6835c6..ed3c0c3 100644
--- a/src/main/java/com/chaitin/xray/test/Main.java
+++ b/src/main/java/com/chaitin/xray/test/Main.java
@@ -3,9 +3,13 @@ package com.chaitin.xray.test;
 
 import com.chaitin.xray.utils.JNAUtil;
 
 public class Main {
     public static void main(String[] args)throws Exception {
-        Process p = Runtime.getRuntime().exec("ls");
-        System.out.println(JNAUtil.getProcessID(p));
+        String context = "!!javax.script.ScriptEngineManager [\n" +
+                "  !!java.net.URLClassLoader [[\n" +
+                "    !!java.net.URL [\"file:./yaml.jar\"]\n" +
+                "  ]]\n" +
+                "]";
+        System.out.println(context);
     }
 }

Vulnerable code: - 内置`JRE`和`xray`的`exe`可以一键启动：`super-xray-0.7-jre-exe.zip`
                Yaml yaml = new Yaml();
        Yaml yaml = new Yaml();
        Yaml yaml = new Yaml();
        Process p = Runtime.getRuntime().exec("ls");
        System.out.println(JNAUtil.getProcessID(p));
Fixed code: - 内置`JRE`的`exe`可以一键启动：`super-xray-0.7-jre-exe.zip`
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.constructor.SafeConstructor;
                Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.constructor.SafeConstructor;
        Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
        Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
        String context = "!!javax.script.ScriptEngineManager [\n" +
                "  !!java.net.URLClassLoader [[\n" +
                "    !!java.net.URL [\"file:./yaml.jar\"]\n" +
                "  ]]\n" +
                "]";
        System.out.println(context);