gadgetinspectot改造

29 篇文章 3 订阅
本文介绍了对GadgetInspector项目进行的定制化改造,包括扩展JNDIS链接检测逻辑,防止函数扫描死循环,并添加NewXstream源点及利用链检测。通过maxRepeatBranchesTimes参数管理和新发现的lookup利用链支持,提升漏洞检测效率。
摘要由CSDN通过智能技术生成

接上一篇 gadget inspector 挖掘利用链
项目地址github
这便主要是对gadget inspectot进行了一些改造:
1、修改gadgetinspector.GadgetChainDiscovery#JNDISlink函数,增加满足条件,主要针对函数lookup的条件

  private boolean JNDISlink(Handle method, InheritanceMap inheritanceMap) {
    if ((inheritanceMap.isSubclassOf(method.getClassReference(),
        new ClassReference.Handle("java/rmi/registry/Registry")) ||
        inheritanceMap.isSubclassOf(method.getClassReference(),
            new ClassReference.Handle("javax/naming/Context")) ||
            method.getClassReference().getName().equals("javax/naming/Context") ||
            method.getClassReference().getName().equals("java/rmi/registry/Registry"))
        && method.getName().equals("lookup")) {
      return true;
    }
    return false;
  }

2、gadgetinspector的算法为了避免因为被扫描代码函数调用函数导致利用链挖掘过程中死循环,每个函数只会反问一次,即如果有3个不同利用链某个环节调用了同一个函数,可能会忽略掉其中两个。
在gadgetinspector.GadgetChainDiscovery#discover函数处增加超参数maxRepeatBranchesTimes,该参数用来设置每个函数可以最多被利用maxRepeatBranchesTimes次,在分支多用的情况下避免出现扫描函数死循环问题:

for (MethodReference.Handle methodImpl : allImpls) {
     GadgetChainLink newLink = new GadgetChainLink(methodImpl,
         graphCall.getTargetArgIndex());
     if (exploredMethods.contains(newLink)) {
       if (chain.links.size() <= ConfigHelper.opLevel) {
         GadgetChain newChain = new GadgetChain(chain, newLink);
         methodsToExploreRepeat.add(newChain);
       }
       // 增加超参数maxRepeatBranchesTimes,解决分支多用问题
       if (exploredMethodsMap.containsKey(newLink)){
         if(exploredMethodsMap.get(newLink) > ConfigHelper.maxRepeatBranchesTimes){
           continue;
         }
         exploredMethodsMap.put(newLink, exploredMethodsMap.get(newLink)+1);
       }
       else {
         exploredMethodsMap.put(newLink, 1);
       }
     }

     GadgetChain newChain = new GadgetChain(chain, newLink);
     if (isSink(methodImpl, graphCall.getTargetArgIndex(), inheritanceMap)) {
       discoveredGadgets.add(newChain);
     } else {
       methodsToExplore.add(newChain);
       exploredMethods.add(newLink);
     }
   }

超参数maxRepeatBranchesTimes需要在类gadgetinspector.ConfigHelper中增加如下变量:

gadgetinspector.ConfigHelper

然后在入口类gadgetinspector.GadgetInspector增加接收代码:

 else if(arg.equals("--maxRepeatBranchesTimes")){
    ConfigHelper.maxRepeatBranchesTimes = Integer.parseInt(args[++argIndex]);
}

3、在gadgetinspector.jackson.JacksonImplementationFinder#getImplementations函数处,增加满足lookup利用链的其他情况

    public Set<MethodReference.Handle> getImplementations(MethodReference.Handle target) {
        Set<MethodReference.Handle> allImpls = new HashSet<>();

        // For jackson search, we don't get to specify the class; it uses reflection to instantiate the
        // class itself. So just add the target method if the target class is serializable.
        if (Boolean.TRUE.equals(serializableDecider.apply(target.getClassReference()))) {
            allImpls.add(target);
        }
        //补充lookup情况
        if(target.getName().equals("lookup") &&
                (target.getClassReference().getName().equals("javax/naming/Context") || target.getClassReference().getName().equals("java/rmi/registry/Registry"))){
            allImpls.add(target);
        }

        return allImpls;
    }

添加自己的xstream检测

首先需要创建一个包,里面创建三个类
在这里插入图片描述

1、创建NewXstreamSourceDiscovery类,该类用于增加source点,即定义入口

package gadgetinspector.newxstream;

import gadgetinspector.ConfigHelper;
import gadgetinspector.SourceDiscovery;
import gadgetinspector.data.*;

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class NewXstreamSourceDiscovery extends SourceDiscovery {
    public static final Set<String> skipList = new HashSet<>();

    static {
        if (!ConfigHelper.skipSourcesFile.isEmpty()) {
            try(BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(ConfigHelper.skipSourcesFile))) {
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    String c;
                    if (!(c = line.split("#")[0].trim()).isEmpty()) {
                        skipList.add(line.trim());
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void discover(Map<ClassReference.Handle, ClassReference> classMap, Map<MethodReference.Handle, MethodReference> methodMap, InheritanceMap inheritanceMap, Map<MethodReference.Handle, Set<GraphCall>> graphCallMap) {

        for (MethodReference.Handle method : methodMap.keySet()) {
            MethodReference methodValue = methodMap.get(method);
            boolean skipFlag = false;
            for (String skipClass:skipList){
                if (method.getClassReference().getName().contains(skipClass)){
                    skipFlag = true;
                    break;
                }
            }
            if (skipFlag){
                continue;
            }
            addDiscoveredSource(new Source(method, 0));

        }
    }
}

2、创建NewXstremImplementationFinder类,该Finder类,基本都是用到SerializableDecider决策者就可以了,不用写什么其他东西

package gadgetinspector.newxstream;

import gadgetinspector.ImplementationFinder;
import gadgetinspector.SerializableDecider;
import gadgetinspector.data.MethodReference;

import java.util.HashSet;
import java.util.Set;

public class NewXstremImplementationFinder implements ImplementationFinder{
    private final SerializableDecider serializableDecider;
    public NewXstremImplementationFinder(SerializableDecider serializableDecider){
        this.serializableDecider = serializableDecider;
    }
    @Override
    public Set<MethodReference.Handle> getImplementations(MethodReference.Handle target) {
        Set<MethodReference.Handle> allImpls = new HashSet<>();

        if (Boolean.TRUE.equals(serializableDecider.apply(target.getClassReference()))) {
            allImpls.add(target);
        }

        return allImpls;
    }
}

3、创建NewXstremSerializableDecider类,反序列化黑名单的机制,如果想要减少已被禁用链的输出,可以在这里加入黑名单。

package gadgetinspector.newxstream;

import gadgetinspector.SerializableDecider;
import gadgetinspector.data.ClassReference;
import gadgetinspector.data.MethodReference;
import gadgetinspector.jackson.JacksonSourceDiscovery;
import gadgetinspector.webservice.WebserviceSourceDiscovery;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class NewXstremSerializableDecider implements SerializableDecider {
    //类是否通过决策的缓存集合
    private final Map<ClassReference.Handle, Boolean> cache = new HashMap<>();
    //类名-方法集合

    private final Map<ClassReference.Handle, Set<MethodReference.Handle>> methodsByClassMap;

    public NewXstremSerializableDecider(Map<MethodReference.Handle, MethodReference> methodMap){
        this.methodsByClassMap  = new HashMap<>();
        for (MethodReference.Handle method : methodMap.keySet()) {
            Set<MethodReference.Handle> classMethods = methodsByClassMap.get(method.getClassReference());
            if (classMethods == null) {
                classMethods = new HashSet<>();
                methodsByClassMap.put(method.getClassReference(), classMethods);
            }
            classMethods.add(method);
        }
    }
    @Override
    public Boolean apply(ClassReference.Handle handle) {
        if (isNoGadgetClass(handle)) {
            return false;
        }
        return Boolean.TRUE;
    }
    private boolean isNoGadgetClass(ClassReference.Handle clazz) {
        if (WebserviceSourceDiscovery.skipList.contains(clazz.getName())) {
            return true;
        }
        return false;
    }
}

4、创建一个NewXstreamDeserializationConfig 继承于 GIConfig,配置NewXstreamDeserializationConfig

package gadgetinspector.config;

import gadgetinspector.ImplementationFinder;
import gadgetinspector.SerializableDecider;
import gadgetinspector.SlinkDiscovery;
import gadgetinspector.SourceDiscovery;
import gadgetinspector.data.ClassReference;
import gadgetinspector.data.InheritanceMap;
import gadgetinspector.data.MethodReference;
import gadgetinspector.newxstream.*;

import java.util.Map;
import java.util.Set;

public class NewXstreamDeserializationConfig implements GIConfig {
    @Override
    public String getName() {
        return "newXstream";
    }

    @Override
    public SerializableDecider getSerializableDecider(Map<MethodReference.Handle, MethodReference> methodMap, InheritanceMap inheritanceMap) {
        return new NewXstremSerializableDecider(methodMap);
    }

    @Override
    public ImplementationFinder getImplementationFinder(Map<MethodReference.Handle, MethodReference> methodMap, Map<MethodReference.Handle, Set<MethodReference.Handle>> methodImplMap, InheritanceMap inheritanceMap, Map<ClassReference.Handle, Set<MethodReference.Handle>> methodsByClass) {
        return new NewXstremImplementationFinder(getSerializableDecider(methodMap, inheritanceMap));
        
    }

    @Override
    public SourceDiscovery getSourceDiscovery() {
        return new NewXstreamSourceDiscovery();
    }

    @Override
    public SlinkDiscovery getSlinkDiscovery() {
        return null;
    }
}

5、将NewXstreamDeserializationConfig添加到配置仓库ConfigRepository
在这里插入图片描述
6、在gadgetinspector.GadgetChainDiscovery中添加sink点,首先添加sink特征函数

private boolean isNewXstreamSink(Handle method, int argIndex, InheritanceMap inheritanceMap) {

    if (method.getName().equals("toString")
            & method.getClassReference().getName().contains("java/lang/CharSequence")) {
      return true;
    }
    return false;
  }

然后加进gadgetinspector.GadgetChainDiscovery#isSink中

if ((ConfigHelper.slinks.isEmpty() || ConfigHelper.slinks.contains("newXstream")) && isNewXstreamSink(method, argIndex, inheritanceMap)) {
      return true;
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值