/** * 处理summary的编码信息 * @param node $node * @param DataFlow $dataFlow * @param block $block * @param fileSummary $fileSummary */ public static function setEncodeInfo($node, $dataFlow, $block, $fileSummary) { global $F_ENCODING_STRING; $funcName = NodeUtils::getNodeFunctionName($node); //发现有编码操作的函数,将编码信息加入至map中 if (in_array($funcName, $F_ENCODING_STRING)) { $dataFlow->getLocation()->addEncoding($funcName); //向上追踪变量,相同变量的净化信息,全部添加 $funcParams = NodeUtils::getNodeFuncParams($node); //traceback $sameVarEncodeInfo = array(); foreach ($funcParams as $param) { $dataFlows = $block->getBlockSummary()->getDataFlowMap(); $dataFlows = array_reverse($dataFlows); $ret = self::encodeSameVarMultiBlockHandler($param, $block, $dataFlows); //如果一个参数没有净化,则未净化 if (!$ret[0]) { $sameVarEncodeInfo = array(); break; } $sameVarEncodeInfo = array_merge($sameVarEncodeInfo, $ret['funcs']); } //加入此变量的净化信息中 foreach ($sameVarEncodeInfo as $funcName) { $dataFlow->getLocation()->addEncoding($funcName); } } //清除解码 EncodingHandler::clearEncodeInfo($funcName, $node, $dataFlow); //print_r($dataFlow); }
/** * 处理赋值性的一些内置函数 * 比如: * $id = urlencode($_GET['id']) ; * @param unknown $part * @param unknown $type * @param unknown $dataFlow */ public static function assignFuncHandler($part, $type, $dataFlow, $funcName) { $single_func = self::getSingleFuncs(); $encoding_convert = array('iconv'); if ($type == "right" && array_key_exists($funcName, $single_func)) { //首先搜索不安全字符的转换函数 if (in_array($funcName, $encoding_convert)) { $oneFunction = new OneFunction($funcName); $dataFlow->getLocation()->addSanitization($oneFunction); } $position = $single_func[$funcName]; $value = $part->args[$position]->value; //解决trim(urlencode($id))的方法嵌套问题 if ($value->getType() == 'Expr_FuncCall') { $new_name = NodeUtils::getNodeFunctionName($value); self::assignFuncHandler($value, $type, $dataFlow, $new_name); } if ($dataFlow->getValue() != null) { return; } $vars = SymbolUtils::getSymbolByNode($value); $dataFlow->setValue($vars); } }
/** * 污点分析的函数 * @param BasicBlock $block 当前基本块 * @param Node $node 当前的函数调用node * @param string $argName 危险参数名 * @param FileSummary 当前文件摘要 */ public function analysis($block, $node, $argName, $fileSummary) { //传入变量本身就是source $varName = substr($argName, 0, strpos($argName, '[')); if (in_array($varName, $this->sourcesArr) || in_array($argName, $this->sourcesArr)) { //报告漏洞 $path = $fileSummary->getPath(); $type = TypeUtils::getTypeByFuncName(NodeUtils::getNodeFunctionName($node)); $this->report($path, $path, $node, $argName, $type); } else { $path = $fileSummary->getPath(); //获取前驱基本块集合并将当前基本量添加至列表 $this->getPrevBlocks($block); $block_list = $this->pathArr; array_push($block_list, $block); //多个基本块的处理 $this->pathArr = array(); $this->multiBlockHandler($block, $argName, $node, $fileSummary); $this->multiFileHandler($block, $argName, $node, $fileSummary); } }
/** * 根据sink方法的名称获取危险参数的位置 * 比如提交mysql_query的调用node,返回危险参数位置array(0) * 如果找不到,默认返回array() * @param Node $node */ public static function getVulArgs($node) { global $F_SINK_ALL, $F_SINK_ARRAY; $funcName = NodeUtils::getNodeFunctionName($node); $nameNum = count($F_SINK_ARRAY); //从上下文中获取用户定义sink $userDefinedSink = UserDefinedSinkContext::getInstance(); $U_SINK_ALL = $userDefinedSink->getAllSinks(); //如果是系统的sink if (key_exists($funcName, $F_SINK_ALL)) { for ($i = 0; $i < $nameNum; $i++) { if (key_exists($funcName, $F_SINK_ARRAY[$i])) { return $F_SINK_ARRAY[$i][$funcName][0]; } } return array(); } //如果是用户的sink if (key_exists($funcName, $U_SINK_ALL)) { foreach ($userDefinedSink->getAllSinkArray() as $value) { if (key_exists($funcName, $value)) { return $U_SINK_ALL[$funcName][0]; } } return array(); } }
/** * @param 函数体 $stmts * @param 函数参数 $params * @return 一个函数的净化信息对象 */ function findSanitizeParam($stmts, $params) { //print_r($stmts); //print_r($params); foreach ($stmts as $node) { $type = $node->getType(); switch ($type) { //function case "Expr_FuncCall": $funcname = NodeUtils::getNodeFunctionName($node); //查找函数是否在净化函数中,净化类别 $ret = $this->isSecureFunction($funcname); if ($ret[0]) { //默认净化函数净化所有参数 foreach ($node->args as $arg) { $argName = NodeUtils::getNodeStringName($arg); $pos = $this->searchPos($argName, $params); if ($pos > -1) { //当函数的第1个参数净化时,数组为0,记为1 $this->oneFunction->addSanitizeParam($pos + 1, $ret['type']); } } } else { //user define function //find function body in context $context = Context::getInstance(); $funcnode = $context->getFunctionBody($funcname); if (!$funcnode) { break; } //递归,return onefunction $next = new SanitizeParamsFinder(null, $funcname); $ret = $next->findSanitizeParam($funcnode->stmts, $funcnode->params); if (!$ret) { break; } //根据return onefunction,加入到this->onefunction foreach ($ret->getSanitizeParams() as $param) { //计算参数位置,因为认为第一个参数设为位置1,而AST树中 是从0开始 $postion = $param['positon'] - 1; $pos = $this->searchPos(NodeUtils::getNodeStringName($node->args[$postion]), $params); if ($pos > -1) { //当函数的第1个参数净化时,数组为0,记为1 $this->oneFunction->addSanitizeParam($pos + 1, $param['type']); } } } break; //class method //class method case "Expr_MethodCall": //class static method //class static method case "Expr_StaticCall": $funcname = NodeUtils::getNodeFunctionName($node); //查找函数是否在净化函数中,净化类别 $ret = $this->isSecureFunction($funcname); if ($ret[0]) { //默认净化函数净化所有参数 foreach ($node->args as $arg) { $argName = NodeUtils::getNodeStringName($arg); $pos = $this->searchPos($argName, $params); if ($pos > -1) { //当函数的第1个参数净化时,数组为0,记为1 $this->oneFunction->addSanitizeParam($pos + 1, $ret['type']); } } } else { //user define function //find function body in context $context = Context::getInstance(); $funcnode = $context->getFunctionBody($funcname); if (!$funcnode) { break; } //递归,return onefunction $next = new SanitizeParamsFinder($this->className, $funcname); $ret = $next->findSanitizeParam($funcnode->stmts, $funcnode->params); if (!$ret) { break; } //根据return onefunction,加入到this->onefunction foreach ($ret->getSanitizeParams() as $param) { //计算参数位置,因为认为第一个参数设为位置1,而AST树中 是从0开始 $postion = $param['positon'] - 1; $pos = $this->searchPos(NodeUtils::getNodeStringName($node->args[$postion]), $params); if ($pos > -1) { //当函数的第1个参数净化时,数组为0,记为1 $this->oneFunction->addSanitizeParam($pos + 1, $param['type']); } } } break; case "Stmt_Return": //处理return中的函数调用 if ($node->expr->getType() != "Expr_FuncCall") { break; } $funcName = NodeUtils::getNodeStringName($node->expr->name); //递归,return onefunction $next = new SanitizeParamsFinder(null, $funcName); $ret = $next->findSanitizeParam(array($node->expr), $node->expr->args); if (!$ret) { break; } //根据return onefunction,加入到this->onefunction foreach ($ret->getSanitizeParams() as $param) { //计算参数位置,因为认为第一个参数设为位置1,而AST树中 是从0开始 $postion = $param['positon'] - 1; $pos = $this->searchPos(NodeUtils::getNodeStringName($node->expr->args[$postion]), $params); if ($pos > -1) { //当函数的第1个参数净化时,数组为0,记为1 $this->oneFunction->addSanitizeParam($pos + 1, $param['type']); } } break; case "Expr_Assign": //处理赋值右边中的函数调用 if ($node->expr->getType() != "Expr_FuncCall") { break; } $funcName = NodeUtils::getNodeStringName($node->expr->name); //递归,return onefunction $next = new SanitizeParamsFinder(null, $funcName); $ret = $next->findSanitizeParam(array($node->expr), $node->expr->args); if (!$ret) { break; } //根据return onefunction,加入到this->onefunction foreach ($ret->getSanitizeParams() as $param) { //计算参数位置,因为认为第一个参数设为位置1,而AST树中 是从0开始 $postion = $param['positon'] - 1; $pos = $this->searchPos(NodeUtils::getNodeStringName($node->expr->args[$postion]), $params); if ($pos > -1) { $this->oneFunction->addSanitizeParam($pos + 1, $param['type']); } } break; default: break; } } if ($this->isSanitizeFunc($this->oneFunction)) { return $this->oneFunction; } }
/** * 净化函数处理函数 * @param funcNode $node * @return null | array(funcName,type) */ public static function SantiniFuncHandler($node, $fileSummary) { global $F_SECURES_ALL; $funcName = NodeUtils::getNodeFunctionName($node); //查看系统净化函数及已查找函数的信息 $ret = self::isSecureFunction($funcName); if ($ret[0]) { $oneFunction = new OneFunction($funcName); $oneFunction->setSanitiType($ret['type']); return $oneFunction; } else { //未查找过函数 $context = Context::getInstance(); $require_array = $fileSummary->getIncludeMap(); $path = $fileSummary->getPath(); $funcBody = $context->getClassMethodBody($funcName, $path, $require_array); if (!$funcBody) { return null; } $visitor = new SanitiFunctionVisitor(); $parser = new PhpParser\Parser(new PhpParser\Lexer\Emulative()); $traverser = new PhpParser\NodeTraverser(); $traverser->addVisitor($visitor); $visitor->funcName = $funcName; $visitor->fileSummary = $fileSummary; $traverser->traverse($funcBody->stmts); if ($visitor->sanitiInfo[0]) { //将净化函数加入净化UserSanitizeFuncContext $oneFunction = new OneFunction($funcName); $oneFunction->setSanitiType($visitor->sanitiInfo['type']); $SanitiFuncContext = UserSanitizeFuncConetxt::getInstance(); $SanitiFuncContext->addFunction($oneFunction); return $oneFunction; } else { return null; } } }
public function leaveNode(Node $node) { //处理过程间代码,即调用的方法定义中的源码 if ($node->getType() == 'Expr_FuncCall' || $node->getType() == 'Expr_MethodCall' || $node->getType() == 'Expr_StaticCall') { //获取到方法的名称 $nodeName = NodeUtils::getNodeFunctionName($node); $ret = NodeUtils::isSinkFunction($nodeName, $this->scan_type); //进行危险参数的辨别 if ($ret[0] == true) { //处理系统内置的sink //找到了mysql_query $cfg = new CFGGenerator(); //array(where)找到危险参数的位置 $args = $ret[1]; if (is_array($args[0])) { $args = $args[0]; } $vars = $this->senstivePostion($node, $this->block, $args); $type = TypeUtils::getTypeByFuncName($nodeName); if ($vars) { //返回处理结果,将多个相关变量位置返回 $this->vars = array_merge($this->vars, $vars); } if ($type) { //返回sink类型 $this->sinkType = $type; } } elseif (array_key_exists($nodeName, $this->sinkContext->getAllSinks())) { //处理已经加入sinksContext用户自定义函数 //处理用户定义的sink $type = TypeUtils::getTypeByFuncName($nodeName); if ($type) { //返回sink类型 $this->sinkType = $type; } $context = Context::getInstance(); $funcName = NodeUtils::getNodeFunctionName($node); $funcBody = $context->getClassMethodBody($funcName, $this->fileSummary->getPath(), $this->fileSummary->getIncludeMap()); if (!$funcBody) { break; } $cfg = new CFGGenerator(); //$this->block->function[$nodeName] $arr = $this->sinkContext->getAllSinks(); $arr = $arr[$nodeName]; foreach ($arr as $pos) { $argName = NodeUtils::getNodeFuncParams($node); $argName = $argName[$pos]; $this->vars = $this->sinkMultiBlockTraceback($argName, $this->block, 0); } } else { } } }