📄 findsqlinjection.java
字号:
INVOKEINTERFACE invoke = (INVOKEINTERFACE) ins; String methodName = invoke.getMethodName(cpg); String interfaceName = invoke.getClassName(cpg); if (methodName.startsWith("execute") && interfaceName.equals("java.sql.Statement")) { return true; } return false; } private boolean isDatabaseSink(Instruction ins, ConstantPoolGen cpg) { return isPreparedStatementDatabaseSink(ins, cpg) || isExecuteDatabaseSink(ins, cpg); } private StringAppendState getStringAppendState(CFG cfg, ConstantPoolGen cpg) throws CFGBuilderException { StringAppendState stringAppendState = new StringAppendState(); String sig = method.getSignature(); sig = sig.substring(0,sig.indexOf(')')); if (sig.indexOf("java/lang/String") >= 0) stringAppendState.setSawInitialTaint(); for (Iterator<Location> i = cfg.locationIterator(); i.hasNext();) { Location location = i.next(); InstructionHandle handle = location.getHandle(); Instruction ins = handle.getInstruction(); if (isConstantStringLoad(location, cpg)) { stringAppendState = updateStringAppendState(location, cpg, stringAppendState); } else if (isStringAppend(ins, cpg)) { stringAppendState.setSawAppend(handle); Location prevLocation = getPreviousLocation(cfg, location, true); if (prevLocation != null && !isSafeValue(prevLocation, cpg)) stringAppendState.setSawUnsafeAppend(handle); } else if (ins instanceof InvokeInstruction) { InvokeInstruction inv = (InvokeInstruction) ins; String sig1 = inv.getSignature(cpg); String sig2 = sig1.substring(sig1.indexOf(')')); if (sig2.indexOf("java/lang/String") >= 0) { String methodName = inv.getMethodName(cpg); String className = inv.getClassName(cpg); if (methodName.equals("valueOf") && className.equals("java.lang.String") && sig1.equals("(Ljava/lang/Object;)Ljava/lang/String;")) { try { TypeDataflow typeDataflow = classContext.getTypeDataflow(method); TypeFrame frame = typeDataflow.getFactAtLocation(location); if (!frame.isValid()) { // This basic block is probably dead continue; } Type operandType = frame.getTopValue(); if (operandType.equals(TopType.instance())) { // unreachable continue; } String sig3 = operandType.getSignature(); if (!sig3.equals("Ljava/lang/String;")) stringAppendState.setSawTaint(handle); } catch (CheckedAnalysisException e) { stringAppendState.setSawTaint(handle); } } else if (className.startsWith("java.lang.String") || className.equals("java.lang.Long") || className.equals("java.lang.Integer") || className.equals("java.lang.Float") || className.equals("java.lang.Double") || className.equals("java.lang.Short") || className.equals("java.lang.Byte") || className.equals("java.lang.Character")) { // ignore it assert true; } else if (methodName.startsWith("to") && methodName.endsWith("String") && methodName.length() > 8) { // ignore it assert true; } else stringAppendState.setSawTaint(handle); } } else if (ins instanceof GETFIELD) { GETFIELD getfield = (GETFIELD) ins; String sig2 = getfield.getSignature(cpg); if (sig2.indexOf("java/lang/String") >= 0) stringAppendState.setSawTaint(handle); } } return stringAppendState; } private boolean isSafeValue(Location location, ConstantPoolGen cpg) throws CFGBuilderException { Instruction prevIns = location.getHandle().getInstruction(); if (prevIns instanceof LDC || prevIns instanceof GETSTATIC) return true; if (prevIns instanceof InvokeInstruction) { String methodName = ((InvokeInstruction) prevIns).getMethodName(cpg); if (methodName.startsWith("to") && methodName.endsWith("String") && methodName.length() > 8) return true; } if (prevIns instanceof AALOAD) { CFG cfg = classContext.getCFG(method); Location prev = getPreviousLocation(cfg, location, true); if (prev != null) { Location prev2 = getPreviousLocation(cfg, prev, true); if (prev2 != null && prev2.getHandle().getInstruction() instanceof GETSTATIC) { GETSTATIC getStatic = (GETSTATIC) prev2.getHandle().getInstruction(); if (getStatic.getSignature(cpg).equals("[Ljava/lang/String;")) return true; } } } return false; } private @CheckForNull InstructionHandle getPreviousInstruction(InstructionHandle handle, boolean skipNops) { while (handle.getPrev() != null) { handle = handle.getPrev(); Instruction prevIns = handle.getInstruction(); if (!(prevIns instanceof NOP && skipNops)) { return handle; } } return null; } private @CheckForNull Location getPreviousLocation(CFG cfg, Location startLocation, boolean skipNops) { Location loc = startLocation; InstructionHandle prev = getPreviousInstruction(loc.getHandle(), skipNops); if (prev != null) return new Location(prev, loc.getBasicBlock()); BasicBlock block = loc.getBasicBlock(); while (true) { block = cfg.getPredecessorWithEdgeType(block, EdgeTypes.FALL_THROUGH_EDGE); if (block == null) return null; InstructionHandle lastInstruction = block.getLastInstruction(); if (lastInstruction != null) return new Location(lastInstruction, block); } } private @CheckForNull InstructionHandle getPreviousInstruction(CFG cfg, Location startLocation, boolean skipNops) { Location loc = startLocation; InstructionHandle prev = getPreviousInstruction(loc.getHandle(), skipNops); if (prev != null) return prev; BasicBlock block = loc.getBasicBlock(); while (true) { block = cfg.getPredecessorWithEdgeType(block, EdgeTypes.FALL_THROUGH_EDGE); if (block == null) return null; InstructionHandle lastInstruction = block.getLastInstruction(); if (lastInstruction != null) return lastInstruction; } } private BugInstance generateBugInstance(JavaClass javaClass, MethodGen methodGen, InstructionHandle handle, StringAppendState stringAppendState) { Instruction instruction = handle.getInstruction(); ConstantPoolGen cpg = methodGen.getConstantPool(); int priority = LOW_PRIORITY; if (stringAppendState.getSawAppend(handle)) { if (stringAppendState.getSawOpenQuote(handle) && stringAppendState.getSawCloseQuote(handle)) { priority = HIGH_PRIORITY; } else if (stringAppendState.getSawComma(handle)) { priority = NORMAL_PRIORITY; } if (!stringAppendState.getSawUnsafeAppend(handle)) { priority += 2; } else if (!stringAppendState.getSawTaint(handle)) { priority ++; } } String description = ""; if (isExecuteDatabaseSink(instruction, cpg)) { description = "SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE"; } else if (isPreparedStatementDatabaseSink(instruction, cpg)) { description = "SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING"; } BugInstance bug = new BugInstance(this, description, priority); bug.addClassAndMethod(methodGen, javaClass.getSourceFileName()); return bug; } Method method; ClassContext classContext; private void analyzeMethod(ClassContext classContext, Method method) throws DataflowAnalysisException, CFGBuilderException { JavaClass javaClass = classContext.getJavaClass(); this.method = method; this.classContext = classContext; MethodGen methodGen = classContext.getMethodGen(method); if (methodGen == null) return; ConstantPoolGen cpg = methodGen.getConstantPool(); CFG cfg = classContext.getCFG(method); StringAppendState stringAppendState = getStringAppendState(cfg, cpg); ConstantDataflow dataflow = classContext.getConstantDataflow(method); for (Iterator<Location> i = cfg.locationIterator(); i.hasNext();) { Location location = i.next(); Instruction ins = location.getHandle().getInstruction(); if (isDatabaseSink(ins, cpg)) { ConstantFrame frame = dataflow.getFactAtLocation(location); Constant value = frame.getStackValue(0); if (!value.isConstantString()) { // TODO: verify it's the same string represented by // stringAppendState // FIXME: will false positive on const/static strings // returns by methods Location prev = getPreviousLocation(cfg, location, true); if (prev == null || !isSafeValue(prev, cpg)) { BugInstance bug = generateBugInstance(javaClass, methodGen, location.getHandle(), stringAppendState); bug.addSourceLine(classContext, methodGen, javaClass.getSourceFileName(), location.getHandle()); bugReporter.reportBug(bug); } } } } } public void report() { }}// vim:ts=4
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -