All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.h3xstream.findsecbugs.injection.xml.XmlInjectionDetector Maven / Gradle / Ivy

/**
 * Find Security Bugs
 * Copyright (c) Philippe Arteau, All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3.0 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.
 */
package com.h3xstream.findsecbugs.injection.xml;

import com.h3xstream.findsecbugs.common.matcher.InvokeMatcherBuilder;
import com.h3xstream.findsecbugs.injection.BasicInjectionDetector;
import com.h3xstream.findsecbugs.injection.InjectionPoint;
import com.h3xstream.findsecbugs.taintanalysis.Taint;
import com.h3xstream.findsecbugs.taintanalysis.TaintFrame;
import com.h3xstream.findsecbugs.taintanalysis.TaintFrameAdditionalVisitor;
import edu.umd.cs.findbugs.BugReporter;
import edu.umd.cs.findbugs.Priorities;
import edu.umd.cs.findbugs.ba.ClassContext;
import edu.umd.cs.findbugs.ba.DataflowAnalysisException;
import org.apache.bcel.classfile.Constant;
import org.apache.bcel.classfile.ConstantUtf8;
import org.apache.bcel.generic.*;

import java.util.List;

import static com.h3xstream.findsecbugs.common.matcher.InstructionDSL.invokeInstruction;

/**
 * Detect string concatenation that appears to be constructing XML or HTML documents.
 *
 * @author baloghadamsoftware, h3xstream
 */
public class XmlInjectionDetector extends BasicInjectionDetector implements TaintFrameAdditionalVisitor {

    private static final String XML_INJECTION_TYPE = "POTENTIAL_XML_INJECTION";
    private static final String[] STRING_CONCAT_CLASS = new String[] {"java/lang/StringBuilder","java/lang/StringBuffer"};

    private static final InvokeMatcherBuilder STRINGBUILDER_APPEND = invokeInstruction() //
            .atClass(STRING_CONCAT_CLASS).atMethod("append");

    private static final boolean DEBUG = false;

    public XmlInjectionDetector(BugReporter bugReporter) {
        super(bugReporter);

        for(String variant: STRING_CONCAT_CLASS) { //Small hack to avoid loading a signature files for two functions.
            addParsedInjectionPoint(variant+".append(Ljava/lang/String;)L"+variant+";",new InjectionPoint(new int[] {0}, XML_INJECTION_TYPE));
        }
        registerVisitor(this);
    }

    @Override
    protected int getPriorityFromTaintFrame(TaintFrame taintFrame, int offset) throws DataflowAnalysisException {
        Taint taint0 = taintFrame.getStackValue(0);
        Taint taint1 = taintFrame.getStackValue(1);

        /**
         * If the value argument passed to append is unsafe (not constant)[1] and not sanitize for XML (XSS_SAFE) [2]
         * and the StringBuilder to which the dynamic value is added is within XML tags [3]
         * [1] && [2] && [3]
         */
        if (!taint0.isSafe() && !taint0.hasTag(Taint.Tag.XSS_SAFE) && taint1.hasTag(Taint.Tag.XML_VALUE)) {
            return Priorities.NORMAL_PRIORITY;
        }
        else {
            return Priorities.IGNORE_PRIORITY;
        }
    }

    @Override
    public void visitInvoke(InvokeInstruction invoke, MethodGen methodGen, TaintFrame frameType, List parameters, ConstantPoolGen cpg) throws DataflowAnalysisException {

        if(STRINGBUILDER_APPEND.matches(invoke,cpg)) {

            Taint appendedTaint = parameters.get(0);
            String appendedString = appendedTaint.getConstantValue();
            if(appendedString!= null) {

                //When the string with a tag is sent to the append function.
                //The StringBuilder class will be tagged as XML_VALUE
                if(appendedString.contains("<") && appendedString.contains(">")) {
                    appendedTaint.addTag(Taint.Tag.XML_VALUE);
                    frameType.getStackValue(0).addTag(Taint.Tag.XML_VALUE);
                }
            }



        }
    }

    @Override
    public void visitReturn(MethodGen methodGen, Taint returnValue, ConstantPoolGen cpg) throws Exception {

    }

    @Override
    public void visitLoad(LoadInstruction instruction, MethodGen methodGen, TaintFrame frameType, int numProduced, ConstantPoolGen cpg) {

    }

    @Override
    public void visitField(FieldInstruction put, MethodGen methodGen, TaintFrame frameType, Taint taint, int numProduced, ConstantPoolGen cpg) throws Exception {

    }

    /**
     * Before we added new tag to the taint analysis and add more effort, here is a linear search on the constant pool.
     * Constant pool include all the constant use in the code of the class. It contains class references and string value.
     *
     * If there are no XML in string in the class, we are add not going to run this additional visitor.
     *
     * @param classContext Information about the class that is about to be analyzed
     * @return
     */
    @Override
    public boolean shouldAnalyzeClass(ClassContext classContext) {
        ConstantPoolGen constantPoolGen = classContext.getConstantPoolGen();
        boolean stringConcat = false;
        boolean hasOpenTagInString = false;
        for (String requiredClass : STRING_CONCAT_CLASS) {
            if (constantPoolGen.lookupUtf8(requiredClass) != -1) {
                stringConcat = true;
                break;
            }
        }
        for(int i=0;i




© 2015 - 2025 Weber Informatics LLC | Privacy Policy