File Editor
Directories:
.. (Back)
Files:
lexer.php
parser.php
sqli.php
Create New File
Create
Edit File: lexer.php
<?php if (defined('WFWAF_VERSION') && !defined('WFWAF_RUN_COMPLETE')) { interface wfWAFLexerInterface { public function nextToken(); } class wfWAFRuleLexer implements wfWAFLexerInterface { const MATCH_IDENTIFIER = '/[a-zA-Z_][\\w_]*/'; const MATCH_SINGLE_STRING_LITERAL = '/\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As'; const MATCH_DOUBLE_STRING_LITERAL = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"/As'; const MATCH_NUMBER_LITERAL = '/-?\d+(\.\d+)?/'; const MATCH_DOT = '/\./'; const MATCH_AND_COMPARISON_OPERATOR = '/&&/'; const MATCH_OR_COMPARISON_OPERATOR = '/\|\|/'; const MATCH_OPEN_PARENTHESIS = '/\(/'; const MATCH_CLOSE_PARENTHESIS = '/\)/'; const MATCH_COMMA = '/,/'; const MATCH_RULE_COMPARISON_END = '/:/'; const MATCH_ASSIGNMENT = '/=/'; const MATCH_SINGLE_LINE_COMMENT = '/(?:#|\/\/)[^\n]*/'; const MATCH_MULTIPLE_LINE_COMMENT = '/\/\*.*?\*\//s'; const MATCH_OPEN_BRACKET = '/\[/'; const MATCH_CLOSE_BRACKET = '/\]/'; const T_RULE_START = 'T_RULE_START'; const T_IDENTIFIER = 'T_IDENTIFIER'; const T_SINGLE_STRING_LITERAL = 'T_SINGLE_STRING_LITERAL'; const T_DOUBLE_STRING_LITERAL = 'T_DOUBLE_STRING_LITERAL'; const T_NUMBER_LITERAL = 'T_NUMBER_LITERAL'; const T_DOT = 'T_DOT'; const T_COMPARISON_OPERATOR = 'T_COMPARISON_OPERATOR'; const T_OPEN_PARENTHESIS = 'T_OPEN_PARENTHESIS'; const T_CLOSE_PARENTHESIS = 'T_CLOSE_PARENTHESIS'; const T_COMMA = 'T_COMMA'; const T_RULE_COMPARISON_END = 'T_RULE_COMPARISON_END'; const T_ASSIGNMENT = 'T_ASSIGNMENT'; const T_SINGLE_LINE_COMMENT = 'T_SINGLE_LINE_COMMENT'; const T_MULTIPLE_LINE_COMMENT = 'T_MULTIPLE_LINE_COMMENT'; const T_OPEN_BRACKET = 'T_OPEN_BRACKET'; const T_CLOSE_BRACKET = 'T_CLOSE_BRACKET'; /** * @var string */ private $rules; /** * @var wfWAFStringScanner */ private $scanner; /** * wfWAFRuleLexer constructor. * @param $rules */ public function __construct($rules) { $this->setRules($rules); $this->scanner = new wfWAFStringScanner($rules); } /** * @return array * @throws wfWAFParserSyntaxError */ public function tokenize() { $tokens = array(); while ($token = $this->nextToken()) { $tokens[] = $token; } return $tokens; } /** * @return bool|wfWAFLexerToken * @throws wfWAFParserSyntaxError */ public function nextToken() { if (!$this->scanner->eos()) { $this->scanner->skip('/\s+/s'); if ($this->scanner->eos()) { return false; } if (($match = $this->scanner->scan(self::MATCH_IDENTIFIER)) !== null) switch (wfWAFUtils::strtolower($match)) { case 'if': return $this->createToken(self::T_RULE_START, $match); case 'and': case 'or': case 'xor': return $this->createToken(self::T_COMPARISON_OPERATOR, $match); default: return $this->createToken(self::T_IDENTIFIER, $match); } else if (($match = $this->scanner->scan(self::MATCH_SINGLE_STRING_LITERAL)) !== null) return $this->createToken(self::T_SINGLE_STRING_LITERAL, $match); else if (($match = $this->scanner->scan(self::MATCH_DOUBLE_STRING_LITERAL)) !== null) return $this->createToken(self::T_DOUBLE_STRING_LITERAL, $match); else if (($match = $this->scanner->scan(self::MATCH_NUMBER_LITERAL)) !== null) return $this->createToken(self::T_NUMBER_LITERAL, $match); else if (($match = $this->scanner->scan(self::MATCH_DOT)) !== null) return $this->createToken(self::T_DOT, $match); else if (($match = $this->scanner->scan(self::MATCH_AND_COMPARISON_OPERATOR)) !== null) return $this->createToken(self::T_COMPARISON_OPERATOR, $match); else if (($match = $this->scanner->scan(self::MATCH_OR_COMPARISON_OPERATOR)) !== null) return $this->createToken(self::T_COMPARISON_OPERATOR, $match); else if (($match = $this->scanner->scan(self::MATCH_OPEN_PARENTHESIS)) !== null) return $this->createToken(self::T_OPEN_PARENTHESIS, $match); else if (($match = $this->scanner->scan(self::MATCH_CLOSE_PARENTHESIS)) !== null) return $this->createToken(self::T_CLOSE_PARENTHESIS, $match); else if (($match = $this->scanner->scan(self::MATCH_COMMA)) !== null) return $this->createToken(self::T_COMMA, $match); else if (($match = $this->scanner->scan(self::MATCH_RULE_COMPARISON_END)) !== null) return $this->createToken(self::T_RULE_COMPARISON_END, $match); else if (($match = $this->scanner->scan(self::MATCH_ASSIGNMENT)) !== null) return $this->createToken(self::T_ASSIGNMENT, $match); else if (($match = $this->scanner->scan(self::MATCH_OPEN_BRACKET)) !== null) return $this->createToken(self::T_OPEN_BRACKET, $match); else if (($match = $this->scanner->scan(self::MATCH_CLOSE_BRACKET)) !== null) return $this->createToken(self::T_CLOSE_BRACKET, $match); else if (($match = $this->scanner->scan(self::MATCH_SINGLE_LINE_COMMENT)) !== null) return $this->createToken(self::T_SINGLE_LINE_COMMENT, $match); else if (($match = $this->scanner->scan(self::MATCH_MULTIPLE_LINE_COMMENT)) !== null) return $this->createToken(self::T_MULTIPLE_LINE_COMMENT, $match); else { $e = new wfWAFParserSyntaxError(sprintf('Invalid character "%s" found on line %d, column %d', $this->scanner->scanChar(), $this->scanner->getLine(), $this->scanner->getColumn())); $e->setParseLine($this->scanner->getLine()); $e->setParseColumn($this->scanner->getColumn()); throw $e; } } return false; } /** * @param $type * @param $value * @return wfWAFLexerToken */ protected function createToken($type, $value) { return new wfWAFLexerToken($type, $value, $this->scanner->getLine(), $this->scanner->getColumn()); } /** * @return string */ public function getRules() { return $this->rules; } /** * @param string $rules */ public function setRules($rules) { $this->rules = rtrim($rules); } } /** * */ class wfWAFLexerToken { private $type; private $value; private $line; private $column; /** * wfWAFRuleToken constructor. * * @param $type * @param $value * @param $line * @param $column */ public function __construct($type, $value, $line, $column) { $this->setType($type); $this->setValue($value); $this->setLine($line); $this->setColumn($column); } /** * @return string */ public function getLowerCaseValue() { return wfWAFUtils::strtolower($this->getValue()); } /** * @return string */ public function getUpperCaseValue() { return wfWAFUtils::strtoupper($this->getValue()); } /** * @return mixed */ public function getType() { return $this->type; } /** * @param mixed $type */ public function setType($type) { $this->type = $type; } /** * @return mixed */ public function getValue() { return $this->value; } /** * @param mixed $value */ public function setValue($value) { $this->value = $value; } /** * @return mixed */ public function getLine() { return $this->line; } /** * @param mixed $line */ public function setLine($line) { $this->line = $line; } /** * @return mixed */ public function getColumn() { return $this->column; } /** * @param mixed $column */ public function setColumn($column) { $this->column = $column; } } class wfWAFParserSyntaxError extends wfWAFException { private $parseLine; private $parseColumn; private $token; /** * @return mixed */ public function getToken() { return $this->token; } /** * @param mixed $token */ public function setToken($token) { $this->token = $token; } /** * @return mixed */ public function getParseLine() { return $this->parseLine; } /** * @param mixed $parseLine */ public function setParseLine($parseLine) { $this->parseLine = $parseLine; } /** * @return mixed */ public function getParseColumn() { return $this->parseColumn; } /** * @param mixed $parseColumn */ public function setParseColumn($parseColumn) { $this->parseColumn = $parseColumn; } } class wfWAFBaseParser { protected $tokens; protected $index; /** @var wfWAFLexerInterface */ protected $lexer; protected $checkpoint=0; public function __construct($lexer) { $this->lexer = $lexer; } /** * @param wfWAFLexerToken $token * @param mixed $type * @return bool */ protected function isTokenOfType($token, $type) { if (is_array($type)) { return $token && in_array($token->getType(), $type); } return $token && $token->getType() === $type; } /** * @param wfWAFLexerToken $token * @param int $type * @param string $message * @throws wfWAFParserSyntaxError */ protected function expectTokenTypeEquals($token, $type, $message = 'Wordfence WAF Syntax Error: Unexpected %s found on line %d, column %d. Expected %s.') { if ($token->getType() !== $type) { $this->triggerSyntaxError($token, sprintf($message, $token->getType(), $token->getLine(), $token->getColumn(), $type)); } } /** * @param wfWAFLexerToken $token * @param array $types * @param string $message * @throws wfWAFParserSyntaxError */ protected function expectTokenTypeInArray($token, $types, $message = 'Wordfence WAF Syntax Error: Unexpected %s found on line %d, column %d') { if (!in_array($token->getType(), $types)) { $this->triggerSyntaxError($token, sprintf($message, $token->getType(), $token->getLine(), $token->getColumn())); } } /** * @param wfWAFLexerToken $token * @param string $message * @throws wfWAFParserSyntaxError */ protected function triggerSyntaxError($token, $message = 'Wordfence WAF Syntax Error: Unexpected %s %s found on line %d, column %d') { $e = new wfWAFParserSyntaxError(sprintf($message, $token->getType(), $token->getValue(), $token->getLine(), $token->getColumn())); $e->setToken($token); $e->setParseLine($token->getLine()); $e->setParseColumn($token->getColumn()); throw $e; } /** * @return wfWAFLexerToken */ protected function currentToken() { return $this->getToken($this->index); } /** * @return bool|wfWAFLexerToken */ protected function nextToken() { $this->index++; return $this->getToken($this->index); } /** * @param string $message * @return wfWAFLexerToken * @throws wfWAFParserSyntaxError */ protected function expectNextToken($message = 'Expected statement') { $this->index++; if ($token = $this->getToken($this->index)) { return $token; } throw new wfWAFParserSyntaxError($message); } /** * @param int $index * @return mixed */ protected function getToken($index) { if (is_array($this->tokens) && array_key_exists($index, $this->tokens)) { return $this->tokens[$index]; } if ($token = $this->getLexer()->nextToken()) { $this->tokens[$index] = $token; return $this->tokens[$index]; } return false; } /** * @return wfWAFLexerInterface */ public function getLexer() { return $this->lexer; } /** * @param wfWAFLexerInterface $lexer */ public function setLexer($lexer) { $this->lexer = $lexer; } /** * @return mixed */ public function getTokens() { return $this->tokens; } /** * @param mixed $tokens */ public function setTokens($tokens) { $this->tokens = $tokens; } protected function setCheckpoint() { $this->checkpoint=$this->index; } protected function reset() { $this->index=$this->checkpoint; } } /** * */ class wfWAFStringScanner { private $string; private $remainingStringCache; private $length; private $pointer; private $remainingStringCachePointer; private $prevPointer; private $match; private $captures; /** * wfWAFStringScanner constructor. * @param $string */ public function __construct($string = null) { if (is_string($string)) { $this->setString($string); } } /** * @param $regex * @return mixed */ public function scan($regex) { $remaining = $this->getRemainingString(); if ($this->regexMatch($regex, $remaining, $matches)) { $matchLen = wfWAFUtils::strlen($matches[0]); if ($matchLen > 0 && wfWAFUtils::strpos($remaining, $matches[0]) === 0) { return $this->setState($matches, $this->getPointer() + $matchLen, $this->getPointer()); } } return $this->setState(); } /** * @param $regex * @return int|null */ public function skip($regex) { return $this->scan($regex) ? wfWAFUtils::strlen($this->getMatch()) : null; } /** * @return mixed */ public function scanChar() { return $this->scan('/./s'); } /** * @param string $regex * @return mixed */ public function check($regex) { $remaining = $this->getRemainingString(); if ($this->regexMatch($regex, $remaining, $matches)) { $matchLen = wfWAFUtils::strlen($matches[0]); if ($matchLen > 0 && wfWAFUtils::strpos($remaining, $matches[0]) === 0) { return $this->setState($matches); } } return $this->setState(); } /** * @param string $regex * @param string $remaining * @param $matches * @return int */ public function regexMatch($regex, $remaining, &$matches) { // $startTime = microtime(true); $result = preg_match($regex, $remaining, $matches); // printf("%s took %f seconds\n", $regex, microtime(true) - $startTime); return $result; } /** * @return bool */ public function eos() { return $this->getPointer() === $this->getLength(); } /** * @return string */ public function getRemainingString() { $pointer = $this->getPointer(); if ($pointer === $this->remainingStringCachePointer && is_string($this->remainingStringCache)) { return $this->remainingStringCache; } $this->remainingStringCache = wfWAFUtils::substr($this->getString(), $pointer); $this->remainingStringCachePointer = $pointer; return $this->remainingStringCache; } /** * @return $this */ public function reset() { $this->remainingStringCache = false; $this->setState(array(), 0, 0); return $this; } /** * The current line of the scanned string. * * @return int */ public function getLine() { if ($this->getPointer() + 1 > $this->getLength()) { return wfWAFUtils::substr_count($this->getString(), "\n") + 1; } return wfWAFUtils::substr_count($this->getString(), "\n", 0, $this->getPointer() + 1) + 1; } /** * The current column of the line of the scanned string. * * @return int */ public function getColumn() { return $this->getPointer() - ((int) wfWAFUtils::strrpos(wfWAFUtils::substr($this->getString(), 0, $this->getPointer() + 1), "\n")) + 1; } /** * @param array $matches * @param int|null $pointer * @param int|null $prevPointer * @return mixed */ protected function setState($matches = array(), $pointer = null, $prevPointer = null) { if ($pointer !== null) { $this->setPointer($pointer); } if ($prevPointer !== null) { $this->setPrevPointer($prevPointer); } if (is_array($matches)) { $this->setCaptures(array_slice($matches, 1)); if (count($matches) > 0) { $this->setMatch($matches[0]); } else { $this->setMatch(null); } } else { $this->setMatch(null); } return $this->getMatch(); } /** * @return string */ public function getString() { return $this->string; } /** * @param string $string * @throws InvalidArgumentException */ public function setString($string) { if (!is_string($string)) { throw new InvalidArgumentException(sprintf('String expected, got [%s]', gettype($string))); } $this->setLength(wfWAFUtils::strlen($string)); $this->string = $string; $this->reset(); } /** * @return int */ public function getLength() { return $this->length; } /** * @param int $length */ protected function setLength($length) { $this->length = $length; } /** * @param int $length */ public function advancePointer($length) { $this->setPointer($this->getPointer() + $length); } /** * @return int */ public function getPointer() { return $this->pointer; } /** * @param int $pointer */ protected function setPointer($pointer) { $this->pointer = $pointer; } /** * @return int */ public function getPrevPointer() { return $this->prevPointer; } /** * @param int $prevPointer */ protected function setPrevPointer($prevPointer) { $this->prevPointer = $prevPointer; } /** * @return mixed */ public function getMatch() { return $this->match; } /** * @param mixed $match */ protected function setMatch($match) { $this->match = $match; } /** * @param null $index * @return mixed */ public function getCaptures($index = null) { if (is_numeric($index)) { return isset($this->captures[$index]) ? $this->captures[$index] : null; } return $this->captures; } /** * @param mixed $captures */ protected function setCaptures($captures) { $this->captures = $captures; } } }
Save Changes
Rename File
Rename