Converter.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  1. <?php
  2. /**
  3. * PHPIDS
  4. *
  5. * Requirements: PHP5, SimpleXML
  6. *
  7. * Copyright (c) 2008 PHPIDS group (https://phpids.org)
  8. *
  9. * PHPIDS is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU Lesser General Public License as published by
  11. * the Free Software Foundation, version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * PHPIDS is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public License
  20. * along with PHPIDS. If not, see <http://www.gnu.org/licenses/>.
  21. *
  22. * PHP version 5.1.6+
  23. *
  24. * @category Security
  25. * @package PHPIDS
  26. * @author Mario Heiderich <mario.heiderich@gmail.com>
  27. * @author Christian Matthies <ch0012@gmail.com>
  28. * @author Lars Strojny <lars@strojny.net>
  29. * @license http://www.gnu.org/licenses/lgpl.html LGPL
  30. * @link http://php-ids.org/
  31. */
  32. /**
  33. * PHPIDS specific utility class to convert charsets manually
  34. *
  35. * Note that if you make use of IDS_Converter::runAll(), existing class
  36. * methods will be executed in the same order as they are implemented in the
  37. * class tree!
  38. *
  39. * @category Security
  40. * @package PHPIDS
  41. * @author Christian Matthies <ch0012@gmail.com>
  42. * @author Mario Heiderich <mario.heiderich@gmail.com>
  43. * @author Lars Strojny <lars@strojny.net>
  44. * @copyright 2007-2009 The PHPIDS Group
  45. * @license http://www.gnu.org/licenses/lgpl.html LGPL
  46. * @version Release: $Id:Converter.php 517 2007-09-15 15:04:13Z mario $
  47. * @link http://php-ids.org/
  48. */
  49. class IDS_Converter
  50. {
  51. /**
  52. * Runs all converter functions
  53. *
  54. * Note that if you make use of IDS_Converter::runAll(), existing class
  55. * methods will be executed in the same order as they are implemented in the
  56. * class tree!
  57. *
  58. * @param string $value the value to convert
  59. *
  60. * @static
  61. * @return string
  62. */
  63. public static function runAll($value)
  64. {
  65. foreach (get_class_methods(__CLASS__) as $method) {
  66. if (strpos($method, 'run') === 0) {
  67. continue;
  68. }
  69. $value = self::$method($value);
  70. }
  71. return $value;
  72. }
  73. /**
  74. * Check for comments and erases them if available
  75. *
  76. * @param string $value the value to convert
  77. *
  78. * @static
  79. * @return string
  80. */
  81. public static function convertFromCommented($value)
  82. {
  83. // check for existing comments
  84. if (preg_match('/(?:\<!-|-->|\/\*|\*\/|\/\/\W*\w+\s*$)|' .
  85. '(?:--[^-]*-)/ms', $value)) {
  86. $pattern = array(
  87. '/(?:(?:<!)(?:(?:--(?:[^-]*(?:-[^-]+)*)--\s*)*)(?:>))/ms',
  88. '/(?:(?:\/\*\/*[^\/\*]*)+\*\/)/ms',
  89. '/(?:--[^-]*-)/ms'
  90. );
  91. $converted = preg_replace($pattern, ';', $value);
  92. $value .= "\n" . $converted;
  93. }
  94. //make sure inline comments are detected and converted correctly
  95. $value = preg_replace('/(<\w+)\/+(\w+=?)/m', '$1/$2', $value);
  96. $value = preg_replace('/[^\\\:]\/\/(.*)$/m', '/**/$1', $value);
  97. $value = preg_replace('/([^\-&])#.*[\r\n\v\f]/m', '$1', $value);
  98. $value = preg_replace('/([^&\-])#.*\n/m', '$1 ', $value);
  99. $value = preg_replace('/^#.*\n/m', ' ', $value);
  100. return $value;
  101. }
  102. /**
  103. * Strip newlines
  104. *
  105. * @param string $value the value to convert
  106. *
  107. * @static
  108. * @return string
  109. */
  110. public static function convertFromWhiteSpace($value)
  111. {
  112. //check for inline linebreaks
  113. $search = array('\r', '\n', '\f', '\t', '\v');
  114. $value = str_replace($search, ';', $value);
  115. // replace replacement characters regular spaces
  116. $value = str_replace('�', ' ', $value);
  117. //convert real linebreaks
  118. return preg_replace('/(?:\n|\r|\v)/m', ' ', $value);
  119. }
  120. /**
  121. * Checks for common charcode pattern and decodes them
  122. *
  123. * @param string $value the value to convert
  124. *
  125. * @static
  126. * @return string
  127. */
  128. public static function convertFromJSCharcode($value)
  129. {
  130. $matches = array();
  131. // check if value matches typical charCode pattern
  132. if (preg_match_all('/(?:[\d+-=\/\* ]+(?:\s?,\s?[\d+-=\/\* ]+)){4,}/ms',
  133. $value, $matches)) {
  134. $converted = '';
  135. $string = implode(',', $matches[0]);
  136. $string = preg_replace('/\s/', '', $string);
  137. $string = preg_replace('/\w+=/', '', $string);
  138. $charcode = explode(',', $string);
  139. foreach ($charcode as $char) {
  140. $char = preg_replace('/\W0/s', '', $char);
  141. if (preg_match_all('/\d*[+-\/\* ]\d+/', $char, $matches)) {
  142. $match = preg_split('/(\W?\d+)/',
  143. (implode('', $matches[0])),
  144. null,
  145. PREG_SPLIT_DELIM_CAPTURE);
  146. if (array_sum($match) >= 20 && array_sum($match) <= 127) {
  147. $converted .= chr(array_sum($match));
  148. }
  149. } elseif (!empty($char) && $char >= 20 && $char <= 127) {
  150. $converted .= chr($char);
  151. }
  152. }
  153. $value .= "\n" . $converted;
  154. }
  155. // check for octal charcode pattern
  156. if (preg_match_all('/(?:(?:[\\\]+\d+[ \t]*){8,})/ims', $value, $matches)) {
  157. $converted = '';
  158. $charcode = explode('\\', preg_replace('/\s/', '', implode(',',
  159. $matches[0])));
  160. foreach ($charcode as $char) {
  161. if (!empty($char)) {
  162. if (octdec($char) >= 20 && octdec($char) <= 127) {
  163. $converted .= chr(octdec($char));
  164. }
  165. }
  166. }
  167. $value .= "\n" . $converted;
  168. }
  169. // check for hexadecimal charcode pattern
  170. if (preg_match_all('/(?:(?:[\\\]+\w+\s*){8,})/ims', $value, $matches)) {
  171. $converted = '';
  172. $charcode = explode('\\', preg_replace('/[ux]/', '', implode(',',
  173. $matches[0])));
  174. foreach ($charcode as $char) {
  175. if (!empty($char)) {
  176. if (hexdec($char) >= 20 && hexdec($char) <= 127) {
  177. $converted .= chr(hexdec($char));
  178. }
  179. }
  180. }
  181. $value .= "\n" . $converted;
  182. }
  183. return $value;
  184. }
  185. /**
  186. * Eliminate JS regex modifiers
  187. *
  188. * @param string $value the value to convert
  189. *
  190. * @static
  191. * @return string
  192. */
  193. public static function convertJSRegexModifiers($value)
  194. {
  195. $value = preg_replace('/\/[gim]+/', '/', $value);
  196. return $value;
  197. }
  198. /**
  199. * Converts from hex/dec entities
  200. *
  201. * @param string $value the value to convert
  202. *
  203. * @static
  204. * @return string
  205. */
  206. public static function convertEntities($value)
  207. {
  208. $converted = null;
  209. //deal with double encoded payload
  210. $value = preg_replace('/&amp;/', '&', $value);
  211. if (preg_match('/&#x?[\w]+/ms', $value)) {
  212. $converted = preg_replace('/(&#x?[\w]{2}\d?);?/ms', '$1;', $value);
  213. $converted = html_entity_decode($converted, ENT_QUOTES, 'UTF-8');
  214. $value .= "\n" . str_replace(';;', ';', $converted);
  215. }
  216. // normalize obfuscated protocol handlers
  217. $value = preg_replace(
  218. '/(?:j\s*a\s*v\s*a\s*s\s*c\s*r\s*i\s*p\s*t\s*:)|(d\s*a\s*t\s*a\s*:)/ms',
  219. 'javascript:', $value
  220. );
  221. return $value;
  222. }
  223. /**
  224. * Normalize quotes
  225. *
  226. * @param string $value the value to convert
  227. *
  228. * @static
  229. * @return string
  230. */
  231. public static function convertQuotes($value)
  232. {
  233. // normalize different quotes to "
  234. $pattern = array('\'', '`', '´', '’', '‘');
  235. $value = str_replace($pattern, '"', $value);
  236. //make sure harmless quoted strings don't generate false alerts
  237. $value = preg_replace('/^"([^"=\\!><~]+)"$/', '$1', $value);
  238. return $value;
  239. }
  240. /**
  241. * Converts SQLHEX to plain text
  242. *
  243. * @param string $value the value to convert
  244. *
  245. * @static
  246. * @return string
  247. */
  248. public static function convertFromSQLHex($value)
  249. {
  250. $matches = array();
  251. if(preg_match_all('/(?:(?:\A|[^\d])0x[a-f\d]{3,}[a-f\d]*)+/im', $value, $matches)) {
  252. foreach($matches[0] as $match) {
  253. $converted = '';
  254. foreach(str_split($match, 2) as $hex_index) {
  255. if(preg_match('/[a-f\d]{2,3}/i', $hex_index)) {
  256. $converted .= chr(hexdec($hex_index));
  257. }
  258. }
  259. $value = str_replace($match, $converted, $value);
  260. }
  261. }
  262. // take care of hex encoded ctrl chars
  263. $value = preg_replace('/0x\d+/m', ' 1 ', $value);
  264. return $value;
  265. }
  266. /**
  267. * Converts basic SQL keywords and obfuscations
  268. *
  269. * @param string $value the value to convert
  270. *
  271. * @static
  272. * @return string
  273. */
  274. public static function convertFromSQLKeywords($value)
  275. {
  276. $pattern = array('/(?:is\s+null)|(like\s+null)|' .
  277. '(?:(?:^|\W)in[+\s]*\([\s\d"]+[^()]*\))/ims');
  278. $value = preg_replace($pattern, '"=0', $value);
  279. $value = preg_replace('/[^\w\)]+\s*like\s*[^\w\s]+/ims', '1" OR "1"', $value);
  280. $value = preg_replace('/null([,"\s])/ims', '0$1', $value);
  281. $value = preg_replace('/\d+\./ims', ' 1', $value);
  282. $value = preg_replace('/,null/ims', ',0', $value);
  283. $value = preg_replace('/(?:between)/ims', 'or', $value);
  284. $value = preg_replace('/(?:and\s+\d+\.?\d*)/ims', '', $value);
  285. $value = preg_replace('/(?:\s+and\s+)/ims', ' or ', $value);
  286. $pattern = array('/(?:not\s+between)|(?:is\s+not)|(?:not\s+in)|' .
  287. '(?:xor|<>|rlike(?:\s+binary)?)|' .
  288. '(?:regexp\s+binary)|' .
  289. '(?:sounds\s+like)/ims');
  290. $value = preg_replace($pattern, '!', $value);
  291. $value = preg_replace('/"\s+\d/', '"', $value);
  292. $value = preg_replace('/(\W)div(\W)/ims', '$1 OR $2', $value);
  293. $value = preg_replace('/\/(?:\d+|null)/', null, $value);
  294. return $value;
  295. }
  296. /**
  297. * Detects nullbytes and controls chars via ord()
  298. *
  299. * @param string $value the value to convert
  300. *
  301. * @static
  302. * @return string
  303. */
  304. public static function convertFromControlChars($value)
  305. {
  306. // critical ctrl values
  307. $search = array(
  308. chr(0), chr(1), chr(2), chr(3), chr(4), chr(5),
  309. chr(6), chr(7), chr(8), chr(11), chr(12), chr(14),
  310. chr(15), chr(16), chr(17), chr(18), chr(19), chr(24),
  311. chr(25), chr(192), chr(193), chr(238), chr(255), '\\0'
  312. );
  313. $value = str_replace($search, '%00', $value);
  314. //take care for malicious unicode characters
  315. $value = urldecode(preg_replace('/(?:%E(?:2|3)%8(?:0|1)%(?:A|8|9)' .
  316. '\w|%EF%BB%BF|%EF%BF%BD)|(?:&#(?:65|8)\d{3};?)/i', null,
  317. urlencode($value)));
  318. $value = urldecode(
  319. preg_replace('/(?:%F0%80%BE)/i', '>', urlencode($value)));
  320. $value = urldecode(
  321. preg_replace('/(?:%F0%80%BC)/i', '<', urlencode($value)));
  322. $value = urldecode(
  323. preg_replace('/(?:%F0%80%A2)/i', '"', urlencode($value)));
  324. $value = urldecode(
  325. preg_replace('/(?:%F0%80%A7)/i', '\'', urlencode($value)));
  326. $value = preg_replace('/(?:%ff1c)/', '<', $value);
  327. $value = preg_replace(
  328. '/(?:&[#x]*(200|820|200|820|zwn?j|lrm|rlm)\w?;?)/i', null,$value
  329. );
  330. $value = preg_replace('/(?:&#(?:65|8)\d{3};?)|' .
  331. '(?:&#(?:56|7)3\d{2};?)|' .
  332. '(?:&#x(?:fe|20)\w{2};?)|' .
  333. '(?:&#x(?:d[c-f])\w{2};?)/i', null,
  334. $value);
  335. $value = str_replace(
  336. array('«', '〈', '<', '‹', '〈', '⟨'), '<', $value
  337. );
  338. $value = str_replace(
  339. array('»', '〉', '>', '›', '〉', '⟩'), '>', $value
  340. );
  341. return $value;
  342. }
  343. /**
  344. * This method matches and translates base64 strings and fragments
  345. * used in data URIs
  346. *
  347. * @param string $value the value to convert
  348. *
  349. * @static
  350. * @return string
  351. */
  352. public static function convertFromNestedBase64($value)
  353. {
  354. $matches = array();
  355. preg_match_all('/(?:^|[,&?])\s*([a-z0-9]{30,}=*)(?:\W|$)/im',
  356. $value,
  357. $matches);
  358. foreach ($matches[1] as $item) {
  359. if (isset($item) && !preg_match('/[a-f0-9]{32}/i', $item)) {
  360. $base64_item = base64_decode($item);
  361. $value = str_replace($item, $base64_item, $value);
  362. }
  363. }
  364. return $value;
  365. }
  366. /**
  367. * Detects nullbytes and controls chars via ord()
  368. *
  369. * @param string $value the value to convert
  370. *
  371. * @static
  372. * @return string
  373. */
  374. public static function convertFromOutOfRangeChars($value)
  375. {
  376. $values = str_split($value);
  377. foreach ($values as $item) {
  378. if (ord($item) >= 127) {
  379. $value = str_replace($item, ' ', $value);
  380. }
  381. }
  382. return $value;
  383. }
  384. /**
  385. * Strip XML patterns
  386. *
  387. * @param string $value the value to convert
  388. *
  389. * @static
  390. * @return string
  391. */
  392. public static function convertFromXML($value)
  393. {
  394. $converted = strip_tags($value);
  395. if ($converted && ($converted != $value)) {
  396. return $value . "\n" . $converted;
  397. }
  398. return $value;
  399. }
  400. /**
  401. * This method converts JS unicode code points to
  402. * regular characters
  403. *
  404. * @param string $value the value to convert
  405. *
  406. * @static
  407. * @return string
  408. */
  409. public static function convertFromJSUnicode($value)
  410. {
  411. $matches = array();
  412. preg_match_all('/\\\u[0-9a-f]{4}/ims', $value, $matches);
  413. if (!empty($matches[0])) {
  414. foreach ($matches[0] as $match) {
  415. $chr = chr(hexdec(substr($match, 2, 4)));
  416. $value = str_replace($match, $chr, $value);
  417. }
  418. $value .= "\n\u0001";
  419. }
  420. return $value;
  421. }
  422. /**
  423. * Converts relevant UTF-7 tags to UTF-8
  424. *
  425. * @param string $value the value to convert
  426. *
  427. * @static
  428. * @return string
  429. */
  430. public static function convertFromUTF7($value)
  431. {
  432. if(preg_match('/\+A\w+-?/m', $value)) {
  433. if (function_exists('mb_convert_encoding')) {
  434. if(version_compare(PHP_VERSION, '5.2.8', '<')) {
  435. $tmp_chars = str_split($value);
  436. $value = '';
  437. foreach($tmp_chars as $char) {
  438. if(ord($char) <= 127) {
  439. $value .= $char;
  440. }
  441. }
  442. }
  443. $value .= "\n" . mb_convert_encoding($value, 'UTF-8', 'UTF-7');
  444. } else {
  445. //list of all critical UTF7 codepoints
  446. $schemes = array(
  447. '+ACI-' => '"',
  448. '+ADw-' => '<',
  449. '+AD4-' => '>',
  450. '+AFs-' => '[',
  451. '+AF0-' => ']',
  452. '+AHs-' => '{',
  453. '+AH0-' => '}',
  454. '+AFw-' => '\\',
  455. '+ADs-' => ';',
  456. '+ACM-' => '#',
  457. '+ACY-' => '&',
  458. '+ACU-' => '%',
  459. '+ACQ-' => '$',
  460. '+AD0-' => '=',
  461. '+AGA-' => '`',
  462. '+ALQ-' => '"',
  463. '+IBg-' => '"',
  464. '+IBk-' => '"',
  465. '+AHw-' => '|',
  466. '+ACo-' => '*',
  467. '+AF4-' => '^',
  468. '+ACIAPg-' => '">',
  469. '+ACIAPgA8-' => '">'
  470. );
  471. $value = str_ireplace(array_keys($schemes),
  472. array_values($schemes), $value);
  473. }
  474. }
  475. return $value;
  476. }
  477. /**
  478. * Converts basic concatenations
  479. *
  480. * @param string $value the value to convert
  481. *
  482. * @static
  483. * @return string
  484. */
  485. public static function convertFromConcatenated($value)
  486. {
  487. //normalize remaining backslashes
  488. if ($value != preg_replace('/(\w)\\\/', "$1", $value)) {
  489. $value .= preg_replace('/(\w)\\\/', "$1", $value);
  490. }
  491. $compare = stripslashes($value);
  492. $pattern = array('/(?:<\/\w+>\+<\w+>)/s',
  493. '/(?:":\d+[^"[]+")/s',
  494. '/(?:"?"\+\w+\+")/s',
  495. '/(?:"\s*;[^"]+")|(?:";[^"]+:\s*")/s',
  496. '/(?:"\s*(?:;|\+).{8,18}:\s*")/s',
  497. '/(?:";\w+=)|(?:!""&&")|(?:~)/s',
  498. '/(?:"?"\+""?\+?"?)|(?:;\w+=")|(?:"[|&]{2,})/s',
  499. '/(?:"\s*\W+")/s',
  500. '/(?:";\w\s*\+=\s*\w?\s*")/s',
  501. '/(?:"[|&;]+\s*[^|&\n]*[|&]+\s*"?)/s',
  502. '/(?:";\s*\w+\W+\w*\s*[|&]*")/s',
  503. '/(?:"\s*"\s*\.)/s',
  504. '/(?:\s*new\s+\w+\s*[+",])/',
  505. '/(?:(?:^|\s+)(?:do|else)\s+)/',
  506. '/(?:[{(]\s*new\s+\w+\s*[)}])/',
  507. '/(?:(this|self)\.)/',
  508. '/(?:undefined)/',
  509. '/(?:in\s+)/');
  510. // strip out concatenations
  511. $converted = preg_replace($pattern, null, $compare);
  512. //strip object traversal
  513. $converted = preg_replace('/\w(\.\w\()/', "$1", $converted);
  514. // normalize obfuscated method calls
  515. $converted = preg_replace('/\)\s*\+/', ")", $converted);
  516. //convert JS special numbers
  517. $converted = preg_replace('/(?:\(*[.\d]e[+-]*[^a-z\W]+\)*)' .
  518. '|(?:NaN|Infinity)\W/ims', 1, $converted);
  519. if ($converted && ($compare != $converted)) {
  520. $value .= "\n" . $converted;
  521. }
  522. return $value;
  523. }
  524. /**
  525. * This method collects and decodes proprietary encoding types
  526. *
  527. * @param string $value the value to convert
  528. *
  529. * @static
  530. * @return string
  531. */
  532. public static function convertFromProprietaryEncodings($value) {
  533. //Xajax error reportings
  534. $value = preg_replace('/<!\[CDATA\[(\W+)\]\]>/im', '$1', $value);
  535. //strip false alert triggering apostrophes
  536. $value = preg_replace('/(\w)\"(s)/m', '$1$2', $value);
  537. //strip quotes within typical search patterns
  538. $value = preg_replace('/^"([^"=\\!><~]+)"$/', '$1', $value);
  539. //OpenID login tokens
  540. $value = preg_replace('/{[\w-]{8,9}\}(?:\{[\w=]{8}\}){2}/', null, $value);
  541. //convert Content and \sdo\s to null
  542. $value = preg_replace('/Content|\Wdo\s/', null, $value);
  543. //strip emoticons
  544. $value = preg_replace(
  545. '/(?:\s[:;]-[)\/PD]+)|(?:\s;[)PD]+)|(?:\s:[)PD]+)|-\.-|\^\^/m',
  546. null,
  547. $value
  548. );
  549. //normalize separation char repetion
  550. $value = preg_replace('/([.+~=*_\-;])\1{2,}/m', '$1', $value);
  551. //normalize multiple single quotes
  552. $value = preg_replace('/"{2,}/m', '"', $value);
  553. //normalize quoted numerical values and asterisks
  554. $value = preg_replace('/"(\d+)"/m', '$1', $value);
  555. //normalize pipe separated request parameters
  556. $value = preg_replace('/\|(\w+=\w+)/m', '&$1', $value);
  557. //normalize ampersand listings
  558. $value = preg_replace('/(\w\s)&\s(\w)/', '$1$2', $value);
  559. //normalize escaped RegExp modifiers
  560. $value = preg_replace('/\/\\\(\w)/', '/$1', $value);
  561. return $value;
  562. }
  563. /**
  564. * This method is the centrifuge prototype
  565. *
  566. * @param string $value the value to convert
  567. * @param IDS_Monitor $monitor the monitor object
  568. *
  569. * @static
  570. * @return string
  571. */
  572. public static function runCentrifuge($value, IDS_Monitor $monitor = null)
  573. {
  574. $threshold = 3.49;
  575. if (strlen($value) > 25) {
  576. //strip padding
  577. $tmp_value = preg_replace('/\s{4}|==$/m', null, $value);
  578. $tmp_value = preg_replace(
  579. '/\s{4}|[\p{L}\d\+\-=,.%()]{8,}/m',
  580. 'aaa',
  581. $tmp_value
  582. );
  583. // Check for the attack char ratio
  584. $tmp_value = preg_replace('/([*.!?+-])\1{1,}/m', '$1', $tmp_value);
  585. $tmp_value = preg_replace('/"[\p{L}\d\s]+"/m', null, $tmp_value);
  586. $stripped_length = strlen(preg_replace('/[\d\s\p{L}\.:,%&\/><\-)!|]+/m',
  587. null, $tmp_value));
  588. $overall_length = strlen(
  589. preg_replace('/([\d\s\p{L}:,\.]{3,})+/m', 'aaa',
  590. preg_replace('/\s{2,}/m', null, $tmp_value))
  591. );
  592. if ($stripped_length != 0
  593. && $overall_length/$stripped_length <= $threshold) {
  594. $monitor->centrifuge['ratio'] =
  595. $overall_length/$stripped_length;
  596. $monitor->centrifuge['threshold'] =
  597. $threshold;
  598. $value .= "\n$[!!!]";
  599. }
  600. }
  601. if (strlen($value) > 40) {
  602. // Replace all non-special chars
  603. $converted = preg_replace('/[\w\s\p{L},.:!]/', null, $value);
  604. // Split string into an array, unify and sort
  605. $array = str_split($converted);
  606. $array = array_unique($array);
  607. asort($array);
  608. // Normalize certain tokens
  609. $schemes = array(
  610. '~' => '+',
  611. '^' => '+',
  612. '|' => '+',
  613. '*' => '+',
  614. '%' => '+',
  615. '&' => '+',
  616. '/' => '+'
  617. );
  618. $converted = implode($array);
  619. $_keys = array_keys($schemes);
  620. $_values = array_values($schemes);
  621. $converted = str_replace($_keys, $_values, $converted);
  622. $converted = preg_replace('/[+-]\s*\d+/', '+', $converted);
  623. $converted = preg_replace('/[()[\]{}]/', '(', $converted);
  624. $converted = preg_replace('/[!?:=]/', ':', $converted);
  625. $converted = preg_replace('/[^:(+]/', null, stripslashes($converted));
  626. // Sort again and implode
  627. $array = str_split($converted);
  628. asort($array);
  629. $converted = implode($array);
  630. if (preg_match('/(?:\({2,}\+{2,}:{2,})|(?:\({2,}\+{2,}:+)|' .
  631. '(?:\({3,}\++:{2,})/', $converted)) {
  632. $monitor->centrifuge['converted'] = $converted;
  633. return $value . "\n" . $converted;
  634. }
  635. }
  636. return $value;
  637. }
  638. }
  639. /**
  640. * Local variables:
  641. * tab-width: 4
  642. * c-basic-offset: 4
  643. * End:
  644. * vim600: sw=4 ts=4 expandtab
  645. */