function var_taint_check($file, $node, string $current_scope) : bool { global $scope, $tainted_by; static $tainted = ['_GET' => '*', '_POST' => '*', '_COOKIE' => '*', '_REQUEST' => '*', '_FILES' => '*', '_SERVER' => ['QUERY_STRING', 'HTTP_HOST', 'HTTP_USER_AGENT', 'HTTP_ACCEPT_ENCODING', 'HTTP_ACCEPT_LANGUAGE', 'REQUEST_URI', 'PHP_SELF', 'argv']]; if (!$node instanceof \ast\Node) { return false; } $parent = $node; while ($node instanceof \ast\Node && $node->kind != \ast\AST_VAR && $node->kind != \ast\AST_MAGIC_CONST) { $parent = $node; if (empty($node->children[0])) { break; } $node = $node->children[0]; } if ($parent->kind == \ast\AST_DIM) { if ($node->children[0] instanceof \ast\Node) { // $$var or something else dynamic is going on, not direct access to a suspivious var return false; } foreach ($tainted as $name => $index) { if ($node->children[0] === $name) { if ($index == '*') { return true; } if ($parent->children[1] instanceof \ast\Node) { // Dynamic index, give up return false; } if (in_array($parent->children[1], $index, true)) { return true; } } } } else { if ($parent->kind == \ast\AST_VAR && !$parent->children[0] instanceof \ast\Node) { if (empty($scope[$current_scope]['vars'][$parent->children[0]])) { if (!superglobal($parent->children[0])) { Log::err(Log::EVAR, "Variable \${$parent->children[0]} is not defined", $file, $parent->lineno); } } else { if (!empty($scope[$current_scope]['vars'][$parent->children[0]]['tainted'])) { $tainted_by = $scope[$current_scope]['vars'][$parent->children[0]]['tainted_by']; return true; } } } } return false; }
function var_type($file, $node, $current_scope, &$taint, $check_var_exists = true) { global $scope, $tainted_by; // Check for $$var or ${...} (whose idea was that anyway?) if ($node->children[0] instanceof \ast\Node && ($node->children[0]->kind == \ast\AST_VAR || $node->children[0]->kind == \ast\AST_BINARY_OP)) { return "mixed"; } if (empty($scope[$current_scope]['vars'][$node->children[0]])) { if ($check_var_exists) { if (!superglobal($node->children[0])) { Log::err(Log::EVAR, "Variable \${$node->children[0]} is not defined", $file, $node->lineno); } } } else { if (!empty($scope[$current_scope]['vars'][$node->children[0]]['tainted'])) { $tainted_by = $scope[$current_scope]['vars'][$node->children[0]]['tainted_by']; $taint = true; } return $scope[$current_scope]['vars'][$node->children[0]]['type'] ?? ''; } return ''; }