/** * @param array $failedParams * @param string $highlightParamFormat * @param string $highlightMatchFormat * @return string */ public function highlightFailedParams($failedParams = array(), $highlightParamFormat = '[param]%s[/param]', $highlightMatchFormat = '[match]%s[/match]') { $highlights = array(); // Cap at 50kb $maxRequestLen = 1024 * 50; $this->highlightParamFormat = $highlightParamFormat; $this->highlightMatchFormat = $highlightMatchFormat; if (is_array($failedParams)) { foreach ($failedParams as $paramKey => $categories) { foreach ($categories as $categoryKey => $failedRules) { foreach ($failedRules as $failedRule) { $rule = $failedRule['rule']; /** @var wfWAFRuleComparisonFailure $failedComparison */ $failedComparison = $failedRule['failedComparison']; $action = $failedRule['action']; $paramKey = $failedComparison->getParamKey(); if (preg_match('/request\\.([a-z0-9]+)(?:\\[(.*?)\\](.*?))?$/i', $paramKey, $matches)) { $global = $matches[1]; if (method_exists('wfWAFRequestInterface', "get" . ucfirst($global))) { $highlight = array('match' => $failedComparison->getMatches()); if (isset($matches[2])) { $highlight['param'] = "{$matches['2']}{$matches['3']}"; } $highlights[$global][] = $highlight; } } } } } } $uri = $this->getURI(); $queryStringPos = wfWAFUtils::strpos($uri, '?'); if ($queryStringPos !== false) { $uri = wfWAFUtils::substr($uri, 0, $queryStringPos); } $queryString = $this->getQueryString(); if ($queryString) { $uri .= '?' . http_build_query($queryString); } if (!empty($highlights['queryString'])) { foreach ($highlights['queryString'] as $matches) { if (!empty($matches['param'])) { $this->highlightMatches = $matches['match']; $uri = preg_replace_callback('/(&|\\?|^)(' . preg_quote(urlencode($matches['param']), '/') . ')=(.*?)(&|$)/', array($this, 'highlightParam'), $uri); } } } if (!empty($highlights['uri'])) { foreach ($highlights['uri'] as $matches) { if ($matches) { } } $uri = sprintf($highlightParamFormat, $uri); } $request = "{$this->getMethod()} {$uri} HTTP/1.1\n"; $hasAuth = false; $auth = $this->getAuth(); if (is_array($this->getHeaders())) { foreach ($this->getHeaders() as $header => $value) { switch (wfWAFUtils::strtolower($header)) { case 'cookie': // TODO: Hook up highlights to cookies $cookies = ''; foreach ($this->getCookies() as $cookieName => $cookieValue) { $cookies .= $cookieName . '=' . urlencode($cookieValue) . '; '; } $request .= 'Cookie: ' . trim($cookies) . "\n"; break; case 'host': $request .= 'Host: ' . $this->getHost() . "\n"; break; case 'authorization': $hasAuth = true; if ($auth) { $request .= 'Authorization: Basic ' . base64_encode($auth['user'] . ':' . $auth['password']) . "\n"; } break; default: $request .= $header . ': ' . $value . "\n"; break; } } } if (!$hasAuth && $auth) { $request .= 'Authorization: Basic ' . base64_encode($auth['user'] . ':' . $auth['password']) . "\n"; } $body = $this->getBody(); $contentType = $this->getHeaders('Content-Type'); if (is_array($body)) { if (wfWAFUtils::stripos($contentType, 'application/x-www-form-urlencoded') === 0) { $body = http_build_query($body); if (!empty($highlights['body'])) { foreach ($highlights['body'] as $matches) { if (!empty($matches['param'])) { $this->highlightMatches = $matches['match']; $body = preg_replace_callback('/(&|^)(' . preg_quote(urlencode($matches['param']), '/') . ')=(.*?)(&|$)/', array($this, 'highlightParam'), $body); } } } } else { if (preg_match('/^multipart\\/form\\-data; boundary=(.*?)$/i', $contentType, $boundaryMatches)) { $boundary = $boundaryMatches[1]; $bodyArray = array(); foreach ($body as $key => $value) { $bodyArray = array_merge($bodyArray, $this->reduceBodyParameter($key, $value)); } $body = ''; foreach ($bodyArray as $param => $value) { if (!empty($highlights['body'])) { foreach ($highlights['body'] as $matches) { if (!empty($matches['param']) && $matches['param'] === $param) { $value = sprintf($this->highlightParamFormat, $value); if (is_array($matches['match'][0])) { $replace = array(); foreach ($matches['match'][0] as $key => $match) { $replace[$match] = sprintf($this->highlightMatchFormat, $match); } if ($replace) { $value = str_replace(array_keys($replace), $replace, $value); } } else { // preg_match $value = str_replace($matches['match'][0], sprintf($this->highlightMatchFormat, $matches['match'][0]), $value); } break; } } } $body .= <<<FORM --{$boundary} Content-Disposition: form-data; name="{$param}" {$value} FORM; } foreach ($this->getFiles() as $param => $file) { $name = array_key_exists('name', $file) ? $file['name'] : ''; if (is_array($name)) { continue; // TODO: implement files as arrays } $mime = array_key_exists('type', $file) ? $file['type'] : ''; $value = ''; $lenToRead = $maxRequestLen - (wfWAFUtils::strlen($request) + wfWAFUtils::strlen($body) + 1); if (array_key_exists('content', $file)) { $value = $file['content']; } else { if ($lenToRead > 0 && file_exists($file['tmp_name'])) { $handle = fopen($file['tmp_name'], 'r'); $value = fread($handle, $lenToRead); fclose($handle); } } if (!empty($highlights['fileNames'])) { foreach ($highlights['fileNames'] as $matches) { if (!empty($matches['param']) && $matches['param'] === $param) { $name = sprintf($this->highlightParamFormat, $name); $name = str_replace($matches['match'][0], sprintf($this->highlightMatchFormat, $matches['match'][0]), $name); break; } } } $body .= <<<FORM --{$boundary} Content-Disposition: form-data; name="{$param}"; filename="{$name}" Content-Type: {$mime} Expires: 0 {$value} FORM; } if ($body) { $body .= "--{$boundary}--\n"; } } } } if (!is_string($body)) { $body = ''; } $request .= "\n" . $body; if (wfWAFUtils::strlen($request) > $maxRequestLen) { $request = wfWAFUtils::substr($request, 0, $maxRequestLen); } return $request; }
/** * @param string $binary * @return wfWAFAttackDataStorageFileEngineRow */ public static function unpack($binary) { $attackLogTime = wfWAFAttackDataStorageFileEngine::unpackMicrotime(wfWAFUtils::substr($binary, 0, 8)); $data = wfWAFAttackDataStorageFileEngine::decompress(wfWAFUtils::substr($binary, 8)); return new self($attackLogTime, $data); }
/** * @param $algo * @param $data * @param $key * @param bool|false $raw_output * @return bool|string */ private static function _hash_hmac($algo, $data, $key, $raw_output = false) { $packs = array('md5' => 'H32', 'sha1' => 'H40'); if (!isset($packs[$algo])) { return false; } $pack = $packs[$algo]; if (wfWAFUtils::strlen($key) > 64) { $key = pack($pack, $algo($key)); } $key = str_pad($key, 64, chr(0)); $ipad = wfWAFUtils::substr($key, 0, 64) ^ str_repeat(chr(0x36), 64); $opad = wfWAFUtils::substr($key, 0, 64) ^ str_repeat(chr(0x5c), 64); $hmac = $algo($opad . pack($pack, $algo($ipad . $data))); if ($raw_output) { return pack($pack, $hmac); } return $hmac; }
/** * @return string * @throws wfWAFRuleException */ public function renderRule() { if (!$this->isActionValid()) { throw new wfWAFRuleException('Invalid action passed to ' . get_class($this) . ', action: ' . var_export($this->getAction(), true)); } $subjectExport = ''; /** @var wfWAFRuleComparisonSubject $subject */ foreach ($this->getSubjects() as $subject) { $subjectExport .= $subject->renderRule() . ", "; } $subjectExport = wfWAFUtils::substr($subjectExport, 0, -2); $expected = $this->getExpected(); return sprintf('%s(%s, %s)', $this->getAction(), $expected instanceof wfWAFRuleVariable ? $expected->renderRule() : wfWAFRule::exportString($expected), $subjectExport); }
/** * 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; }
/** * @todo Proxy settings * @param wfWAFHTTP $request * @return wfWAFHTTPResponse|bool */ public function send($request) { $url = $request->getUrl(); if ($queryString = $request->getQueryString()) { if (is_array($queryString)) { $queryString = http_build_query($queryString); } $url .= (wfWAFUtils::strpos($url, '?') !== false ? '&' : '?') . $queryString; } $ch = curl_init($url); switch (wfWAFUtils::strtolower($request->getMethod())) { case 'post': curl_setopt($ch, CURLOPT_POST, 1); break; } if ($body = $request->getBody()) { curl_setopt($ch, CURLOPT_POSTFIELDS, $body); } if ($auth = $request->getAuth()) { curl_setopt($ch, CURLOPT_USERPWD, $auth['user'] . ':' . $auth['password']); } if ($cookies = $request->getCookies()) { if (is_array($cookies)) { $cookies = self::buildCookieString($cookies); } curl_setopt($ch, CURLOPT_COOKIE, $cookies); } if ($headers = $request->getHeaders()) { if (is_array($headers)) { $_headers = array(); foreach ($headers as $header => $value) { $_headers[] = $header . ': ' . $value; } curl_setopt($ch, CURLOPT_HTTPHEADER, $_headers); } } curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 5); curl_setopt($ch, CURLOPT_HEADER, 1); $curlResponse = curl_exec($ch); if ($curlResponse !== false) { $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $header = wfWAFUtils::substr($curlResponse, 0, $headerSize); $body = wfWAFUtils::substr($curlResponse, $headerSize); $response = new wfWAFHTTPResponse(); $response->setBody($body); $response->setHeaders($header); return $response; } return false; }
/** * @return mixed|string * @throws wfWAFRuleParserSyntaxError */ private function expectLiteral() { $expectedToken = $this->expectNextToken(); $this->expectTokenTypeInArray($expectedToken, array(wfWAFRuleLexer::T_SINGLE_STRING_LITERAL, wfWAFRuleLexer::T_DOUBLE_STRING_LITERAL, wfWAFRuleLexer::T_IDENTIFIER, wfWAFRuleLexer::T_NUMBER_LITERAL, wfWAFRuleLexer::T_OPEN_BRACKET)); if ($expectedToken->getType() === wfWAFRuleLexer::T_SINGLE_STRING_LITERAL) { // Remove quotes, strip slashes $value = wfWAFUtils::substr($expectedToken->getValue(), 1, -1); $value = str_replace("\\'", "'", $value); } else { if ($expectedToken->getType() === wfWAFRuleLexer::T_DOUBLE_STRING_LITERAL) { // Remove quotes, strip slashes $value = wfWAFUtils::substr($expectedToken->getValue(), 1, -1); $value = str_replace('\\"', '"', $value); } else { if ($expectedToken->getType() === wfWAFRuleLexer::T_IDENTIFIER) { // Remove quotes, strip slashes $value = new wfWAFRuleVariable($this->getWAF(), $expectedToken->getValue()); } else { if ($expectedToken->getType() === wfWAFRuleLexer::T_OPEN_BRACKET) { $value = array(); while (true) { $nextToken = $this->expectNextToken(); if ($nextToken->getType() === wfWAFRuleLexer::T_CLOSE_BRACKET) { break; } if ($nextToken->getType() === wfWAFRuleLexer::T_COMMA) { continue; } $this->index--; $value[] = $this->expectLiteral(); } } else { $value = $expectedToken->getValue(); } } } } return $value; }