1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
vuln_scanner.php
См. документацию.
1<?php
3
4if (!defined("T_BAD_CHARACTER")) define("T_BAD_CHARACTER", 401);
5
7{
8 public $line = 0;
9 public $start = 0;
10 public $end = 0;
11 public $comment = '';
12 public $tokens = array();
13 public $dependencies = array();
14 public $tainted_vars = array();
15 public $id = 0;
16
18 {
19 $this->line = $line;
20 $this->start = $start;
21 $this->end = $end;
22 $this->comment = $comment;
23 $this->tokens = $tokens;
24 $this->dependencies = $dependencies;
25 $this->tainted_vars = $tainted_vars;
26 $this->id = $id;
27 }
28}
29
31{
32 public $declares = array();
33 public $have_user_input = false;
34 public $secure = false;
35 public $name = '';
37
39 {
40 $this->name = $name;
41 $this->have_user_input = false;
42 $this->declares = array();
43 $this->secure = false;
44 $this->requestInitialization = true;
45 }
46
47 public function newDeclare($id, $line, $start, $end, $tokens, $comment, $dependencies, $tainted_vars)
48 {
49 $this->declares[] = new CVariableDeclare($id, $line, $start, $end, $tokens, $comment, $dependencies, $tainted_vars);
50 }
51}
52
53class CVuln
54{
55 public $comment = '';
56 public $tokens = array();
57 public $dependencies = array();
58 public $tainted_vars = array();
59 public $name = '';
60 public $line = 0;
61 public $filename = '';
62 public $traverse = '';
63 public $additional_text = '';
64
66 {
67 $this->tokens = $tokens;
68 $this->filename = $filename;
69 $this->line = $line;
70 $this->name = $name;
71 $this->dependencies = $dependencies;
72 $this->tainted_vars = $tainted_vars;
73 $this->comment = $comment;
74 $this->traverse = '';
75 $this->additional_text = '';
76 }
77
78}
79
81{
82
83 public $vuln_count = 0;
84 public $arResult = array();
85
86 private $tokens = array();
87 private $variables = array();
88 private $template = '';
89 private $file_history = array();
90 private $current_file = '';
91 private $scan_functions = array();
92 private $tokens_type = array();
93 private $vuln_func = array();
94 private $sec_func = array();
95 private $v_userinput = array();
96 private $mp_mode = false;
97 private $color = array();
98 private $securing_list = array();
99 private $tainted_vars = array();
100 private $comment = '';
101 private $braces = 0;
102 private $dependency = array();
103 private $last_dependency = array();
104 private $dependencies = array();
105 private $dependency_line = 0;
106 private $scanning_file = '';
107 private $init_functions = array();
108 private $search_xss = true;
109 private $global_xss_ignore = false;
110
111 function __construct($file_name, $arParams, $template = '.default', $component_template = '')
112 {
113 $this->scanning_file = $file_name;
114 $this->source_functions = array();
115 $this->tokens_type = $arParams['TOKENS_TYPES'];
116 $this->vuln_func = $arParams['VULN_FUNCTIONS'];
117 $this->sec_func = $arParams['SECURING_FUNCTIONS'];
118 $this->v_userinput = $arParams['USER_INPUTS'];
119 $this->init_functions = $arParams['INIT_FUNCTIONS'];
120
121 $this->securing_list = array();
122 $this->variables = array();
123
124 $this->mp_mode = $arParams['MP_mode'];
125 $this->arParams = $arParams;
126 $this->arResult = array();
127 $this->tainted_vars = array();
128
129 $this->template = $template;
130 $this->comment = '';
131 $this->dependency = array();
132 $this->last_dependency = array();
133 $this->dependencies = array();
134 $this->dependency_line = 'syntax_error';
135 $this->braces = 0;
136
137 $this->scan_functions = array_merge(
138 $this->vuln_func['XSS'],
139 $this->vuln_func['CODE'],
140 $this->vuln_func['FILE_INCLUDE'],
141 $this->vuln_func['EXEC'],
142 $this->vuln_func['DATABASE'],
143 $this->vuln_func['OTHER']
144 );
145
146 $this->color = $arParams['COLORS'];
147 $this->file_history[] = $file_name;
148 $this->current_file = end($this->file_history);
149 $this->tokens = $this->tokenize(file_get_contents($file_name), $component_template);
150 $this->vuln_count = 0;
151 $this->search_xss = true;
152 $this->global_xss_ignore = false;
153 }
154
155 private function getTokensInfo($tokens, $var_declare = true, $function = '')
156 {
157 $arResult = array();
158
159 $this->securing_list = array();
160
161 if ($function === 'unserialize')
162 {
163 foreach ($tokens as $token)
164 {
165 if (is_array($token) && isset($token[1]) && $token[1] === "'allowed_classes'")
166 {
167 return false;
168 }
169 }
170 }
171
172 $braces = 0;
173 $c_params = 1;
174 $skip = false;
175 $unsecure = false;
176 $secure = false;
177 $cur_brace = -1;
178
179 for ($i = 0, $count = count($tokens); $i < $count; $i++)
180 {
181 if(is_array($tokens[$i]))
182 {
183 $token = $tokens[$i][0];
184 $token_value = $tokens[$i][1];
185 if($token === T_DOUBLE_COLON || $token === T_OBJECT_OPERATOR)
186 return false;
187
188 elseif($token === T_VARIABLE)
189 {
190 if($var_declare || $this->scan_functions[$function][0] === 0 || in_array($c_params, $this->scan_functions[$function][0]))
191 {
192 if(
193 (
194 isset($tokens[$i - 1])
195 && is_array($tokens[$i - 1])
196 && in_array($tokens[$i - 1][0], $this->tokens_type['CASTS'])
197 )
198 || (isset($tokens[$i + 1]) && in_array($tokens[$i + 1], $this->tokens_type['ARITHMETIC_STR']))
199 || (isset($tokens[$i - 1]) && in_array($tokens[$i - 1], $this->tokens_type['ARITHMETIC_STR']))
200 || (
201 isset($tokens[$i + 1])
202 && is_array($tokens[$i + 1])
203 && (in_array($tokens[$i + 1][0], $this->tokens_type['ARITHMETIC'])
204 || in_array($tokens[$i + 1][0], $this->tokens_type['OPERATOR'])
205 || in_array($tokens[$i + 1][0], $this->tokens_type['LOGICAL'])
206 )
207 )
208 || (
209 isset($tokens[$i - 1])
210 && is_array($tokens[$i - 1])
211 && (
212 in_array($tokens[$i - 1][0], $this->tokens_type['ARITHMETIC'])
213 || in_array($tokens[$i - 1][0], $this->tokens_type['OPERATOR'])
214 || in_array($tokens[$i - 1][0], $this->tokens_type['LOGICAL'])
215 )
216 )
217 )
218 {
219 $skip = true;
220 }
221 else
222 {
223 if(!in_array($token_value, array_keys($arResult)))
224 {
225 /*if($var_declare)
226 {*/
227 if(in_array($token_value, $this->v_userinput) && ($var_declare || !$secure || $unsecure))
228 {
229
230 $arResult[$token_value]['have_user_input'] = true;
231 $arResult[$token_value]['secure'] = $secure;
232 $arResult[$token_value]['var_name'] = $token_value;
233 $arResult[$token_value]['requestInitialization'] = true;
234 }
235 elseif(isset($this->variables[$val = $this->getVarName($tokens[$i])]))
236 {
237 if($this->variables[$val]->have_user_input && ($var_declare || !$this->variables[$val]->secure || $unsecure))
238 {
239 $arResult[$token_value]['have_user_input'] = true;
240 $arResult[$token_value]['secure'] = ($this->variables[$val]->secure && !$unsecure) ? true : $secure;
241 $arResult[$token_value]['var_name'] = $val;
242 $arResult[$token_value]['requestInitialization'] = $this->variables[$val]->requestInitialization;
243 }
244 //break;
245 }
246 elseif((isset($this->variables[$token_value]) && $this->variables[$token_value]->have_user_input)
247 && ($var_declare || !$this->variables[$token_value]->secure || $unsecure))
248 {
249 $arResult[$token_value]['have_user_input'] = true;
250 $arResult[$token_value]['secure'] = ($this->variables[$token_value]->secure && !$unsecure) ? true : $secure;
251 $arResult[$token_value]['var_name'] = $token_value;
252 $arResult[$token_value]['requestInitialization'] = $this->variables[$token_value]->requestInitialization;
253 //break;
254 }
255 /*}
256 else
257 {
258 if(!$secure && (in_array($token_value, $this->v_userinput) || (isset($this->variables[$token_value]) && $this->variables[$token_value]->have_user_input && (!$this->variables[$token_value]->secure || $unsecure))))
259 {
260 $arResult[$token_value]['have_user_input'] = true;
261 //$arResult[]['secure'] = $secure;
262 $arResult[$token_value]['var_name']=$token_value;
263 }
264 }*/
265 }
266 }
267 }
268 }
269 elseif($cur_brace === -1 && $token === T_STRING
270 && in_array($token_value, $this->sec_func['INSTRING'])
271 )
272 {
273 $unsecure = true;
274 $secure = false;
275 $cur_brace = $braces;
276 }
277 elseif(!$unsecure && ($token === T_STRING
278 && (
279 in_array($token_value, $this->sec_func['SECURES_ALL'])
280 || in_array($token_value, $this->sec_func['STRING'])
281 || (
282 isset($this->scan_functions[$function][1])
283 && is_array($this->scan_functions[$function][1])
284 && in_array($token_value, $this->scan_functions[$function][1])
285 )
286 ))
287 || (in_array($token, $this->tokens_type['CASTS']) && $tokens[$i + 1] === '(')
288 )
289 {
290 $this->securing_list[] = $token_value;
291 $secure = true;
292
293 $cur_brace = $braces;
294 $braces++;
295 $i++;
296 }
297 elseif($token === T_ISSET || ($token === T_STRING && str_starts_with($token_value, 'is_')))
298 {
299 $skip = true;
300 }
301 }
302 elseif($braces === 1 && $tokens[$i] === ', ')
303 {
304 $c_params++;
305 $skip = false;
306 }
307 elseif($tokens[$i] === '(')
308 {
309 $braces++;
310 }
311 elseif($tokens[$i] === ')')
312 {
313 $braces--;
314 if($cur_brace === $braces)
315 {
316 $cur_brace = -1;
317 $unsecure = false;
318 $secure = false;
319 }
320 }
321
322 if($skip)
323 {
324 while (($i + 1 < $count) && !($tokens[$i + 1] === ', '))
325 {
326 if($tokens[$i + 1] === ')')
327 $braces--;
328 $i++;
329 }
330 $skip = false;
331 }
332 }
333
334 if(!empty($arResult))
335 {
336 $secure = true;
337 foreach ($arResult as $res)
338 {
339 if($res['secure'] === false)
340 {
341 $secure = false;
342 break;
343 }
344 }
345
346 $requestInitialization = false;
347 foreach ($arResult as $res)
348 {
349 if($res['requestInitialization'] === true)
350 {
351 $requestInitialization = true;
352 break;
353 }
354 }
355
356 return array($secure, $arResult, $requestInitialization);
357 }
358
359 return false;
360 }
361
362 private function dependencyHave($tokens, $type)
363 {
364 if (!is_array($tokens))
365 {
366 return false;
367 }
368 for ($i = 1, $tokens_count = count($tokens) - 1; $i < $tokens_count; $i++)
369 {
370 if(is_array($tokens[$i]))
371 {
372 switch ($type)
373 {
374 case 'XSS':
375 if($tokens[$i][0] === T_STRING && $tokens[$i - 1] !== '!' && $tokens[$i][1] === 'check_bitrix_sessid')
376 return true;
377 break;
378 case '!XSS':
379 if($tokens[$i][0] === T_STRING && $tokens[$i - 1] === '!' && $tokens[$i][1] === 'check_bitrix_sessid')
380 return true;
381 break;
382 }
383 }
384 }
385 return false;
386 }
387
388 public function process()
389 {
390 $this->objects = array();
391 for ($i = 0, $tokens_count = count($this->tokens); $i < $tokens_count; $i++)
392 {
393
394 if((time() - $this->arParams['time_start']) >= $this->arParams['time_out'])
395 return false;
396
397 if(is_array($this->tokens[$i]))
398 {
399 $token = $this->tokens[$i][0];
400 $token_value = $this->tokens[$i][1];
401 $cur_line = $this->tokens[$i][2];
402
403 if($token === T_VARIABLE)
404 {
405 if($this->tokens[$i + 1] === '=' || (is_array($this->tokens[$i + 1]) && in_array($this->tokens[$i + 1][0], $this->tokens_type['ASSIGNMENT'])))
406 {
407 if (
408 is_array($this->tokens[$i + 2]) && ($this->tokens[$i + 2][0] === T_NEW)
409 && ($className = $this->getClassName($i + 3))
410 )
411 {
412 $this->objects[$token_value] = ltrim(strtoupper($className), '\\');
413 $i += $this->getBraceEnd($this->tokens, $i);
414 }
415 if(!(isset($this->tokens[$i + 2]) && is_array($this->tokens[$i + 2]) && $this->tokens[$i + 2][0] === T_ARRAY))
416 $this->addVariable($this->tokens[$i], $i, $cur_line, $i, $this->getBraceEnd($this->tokens, $i), '');
417 else
418 $i += $this->getBraceEnd($this->tokens, $i);
419 }
420 }
421 elseif($token === T_STRING && in_array($token_value, $this->init_functions))
422 {
423 if($this->tokens[$i + 1] === '(' && is_array($this->tokens[$i + 2]) && $this->tokens[$i + 3] === ')')
424 if(isset($this->variables[$val = $this->getVarName($this->tokens[$i + 2])]))
425 unset($this->variables[$val]);
426 }
427 elseif(
428 in_array($token, $this->tokens_type['FUNCTIONS'])
429 || ($this->search_xss && !$this->global_xss_ignore && in_array($token, $this->tokens_type['XSS']))
430 || in_array($token, $this->tokens_type['INCLUDES'])
431 )
432 {
433 if(in_array($token, $this->tokens_type['INCLUDES']))
434 {
435 $component_template = '';
436 //$additional_tokens=array();
437 if($token == T_INCLUDE_COMPONENT)
438 {
439 if(!$this->mp_mode) //not done yet
440 {
441 $component_name = '';
442 if($this->tokens[$i + 1] === '(' && $this->tokens[$i + 2][0] === T_CONSTANT_ENCAPSED_STRING)
443 {
444 //if(!empty(substr($this->tokens[$i+2][1], 1, -1)))
445 $component_name = substr($this->tokens[$i + 2][1], 1, -1);
446 }
447 $component_name = strtolower($component_name);
448 if(empty($component_name)) // || strpos($component_name, 'bitrix:') === 0)
449 continue;
450
451 $component_name = "/".str_replace(":", "/", $component_name);
452
453 if(is_file($this->arParams['doc_root_path'].'/bitrix/components'.$component_name.'/component.php'))
454 $inc_file = $this->arParams['doc_root_path'].'/bitrix/components'.$component_name.'/component.php';
455 else
456 continue;
457
458 if(
459 $this->current_file === $inc_file
460 || in_array($inc_file, $this->file_history)
461 )
462 {
463 // Recursion detected
464 continue;
465 }
466
467 if($this->tokens[$i + 1] === '(' && $this->tokens[$i + 4][0] === T_CONSTANT_ENCAPSED_STRING)
468 $component_template = substr($this->tokens[$i + 4][1], 1, -1);
469
470 //$additional_tokens=array(array(T_VARIABLE, '$arParams', 0), '=', array(T_CONSTANT_ENCAPSED_STRING, ' ', 0), ';', array(T_VARIABLE, '$arResult', 0), '=', array(T_CONSTANT_ENCAPSED_STRING, ' ', 0), ';');
471 $scanner = new CVulnScanner($inc_file, $this->arParams, $this->template, $component_template);
472 $result = $scanner->process();
473 if($result !== false)
474 {
475 if(!empty($scanner->arResult))
476 $this->arResult = array_merge($this->arResult, $scanner->arResult);
477 $this->vuln_count += $scanner->vuln_count;
478 }
479 else
480 {
481 return false;
482 }
483
484 unset($scanner);
485 continue;
486 }
487 else
488 {
489 continue;
490 }
491 }
492 //including result_modifier.php
493 elseif($token == T_INCLUDE_RESULT_MODIFIER)
494 {
495 if(!$this->mp_mode)
496 {
497 $skip = 1;
498 $component_path = array_pop(explode('bitrix/components', dirname($this->current_file)));
499 $component_template = (!empty($this->tokens[$i][3]) ? $this->tokens[$i][3] : '.default');
500 if(is_file($this->arParams['doc_root_path'].'/bitrix/templates/'.$this->template.'/components'.$component_path.'/'.$component_template.'/result_modifier.php'))
501 $inc_file = $this->arParams['doc_root_path'].'/bitrix/templates/'.$this->template.'/components'.$component_path.'/'.$component_template.'/result_modifier.php';
502 elseif(is_file($this->arParams['doc_root_path'].'/bitrix/templates/'.$component_template.'/components'.$component_path.'/.default/result_modifier.php'))
503 $inc_file = $this->arParams['doc_root_path'].'/bitrix/templates/'.$component_template.'/components'.$component_path.'/.default/result_modifier.php';
504 else
505 $inc_file = dirname($this->current_file).'/templates/'.$component_template.'/result_modifier.php';
506
507 unset($component_path);
508 }
509 else
510 {
511 continue;
512 }
513 }
514 //component template including
515 elseif($token == T_INCLUDE_COMPONENTTEMPLATE)
516 {
517 if(!$this->mp_mode)
518 {
519 $template_name = 'template';
520 $component_template = (!empty($this->tokens[$i][3]) ? $this->tokens[$i][3] : '.default');
521 $skip = 3;
522 if($this->tokens[$i + 1] === '(' && $this->tokens[$i + 2][0] === T_CONSTANT_ENCAPSED_STRING)
523 {
524 $tmp = substr($this->tokens[$i + 2][1], 1, -1);
525 if(!empty($tmp))
526 $template_name = $tmp;
527 unset($tmp);
528 }
529 elseif($this->tokens[$i + 1] === '(' && $this->tokens[$i + 2] === ')')
530 {
531 $skip = 2;
532 }
533 $component_path = array_pop(explode('bitrix/components', dirname($this->current_file)));
534 if(is_file($this->arParams['doc_root_path'].'/bitrix/templates/'.$this->template.'/components'.$component_path.'/'.$component_template.'/'.$template_name.'.php'))
535 $inc_file = $this->arParams['doc_root_path'].'/bitrix/templates/'.$this->template.'/components'.$component_path.'/'.$component_template.'/'.$template_name.'.php';
536 elseif(is_file($this->arParams['doc_root_path'].'/bitrix/templates/.default/components'.$component_path.'/'.$component_template.'/'.$template_name.'.php'))
537 $inc_file = $this->arParams['doc_root_path'].'/bitrix/templates/.default/components'.$component_path.'/'.$component_template.'/'.$template_name.'.php';
538 else
539 $inc_file = dirname($this->current_file).'/templates/'.$component_template.'/'.$template_name.'.php';
540
541
542 unset($component_path);
543 }
544 else
545 {
546 continue;
547 }
548 }
549 // include('xxx')
550 elseif((($this->tokens[$i + 1] === '('
551 && $this->tokens[$i + 2][0] === T_CONSTANT_ENCAPSED_STRING
552 && $this->tokens[$i + 3] === ')')
553 // include 'xxx'
554 || (is_array($this->tokens[$i + 1])
555 && $this->tokens[$i + 1][0] === T_CONSTANT_ENCAPSED_STRING
556 && $this->tokens[$i + 2] === ';'))
557 )
558 {
559 if($this->tokens[$i + 1] === '(')
560 {
561 $inc_file = substr($this->tokens[$i + 2][1], 1, -1);
562 $skip = 5;
563 }
564 else
565 {
566 $inc_file = substr($this->tokens[$i + 1][1], 1, -1);
567 $skip = 3;
568 }
569 }
570 else
571 {
572 $inc_file = $this->getTokensValue(
573 $this->current_file, array_slice($this->tokens, $i + 1, $c = $this->getBraceEnd($this->tokens, $i + 1) + 1));
574 $skip = $c + 1;
575 }
576
577
578 $try_file = $inc_file;
579 if(!is_file($try_file)) // && strpos($try_file, $this->arParams['path'] !== 0))
580 {
581 $try_file = dirname($this->current_file).'/'.$inc_file;
582 $try_file = str_replace('//', '/', $try_file);
583 }
584
585 //not including bitrix core, too hard:(
586 if(is_file($try_file) && !preg_match($this->arParams['PREG_FOR_SKIP_INCLUDE'], $inc_file))
587 {
588 if(
589 $this->current_file !== realpath($try_file) // Circle including
590 && !in_array(realpath($try_file), $this->file_history)
591 )
592 {
593 if($file = file_get_contents($try_file))
594 {
595 $inc_tokens = $this->tokenize($file, $component_template);
596 $this->tokens = array_merge(array_slice($this->tokens, 0, $i + $skip), $inc_tokens, array(array(T_INCLUDE_END, 0, $inc_file)), array_slice($this->tokens, $i + $skip));
597
598 $tokens_count = count($this->tokens);
599 $this->current_file = & realpath($try_file);
600 $this->file_history[] = $try_file;
601
602 $this->comment = str_replace(realpath(trim($this->arParams['path'])), '', realpath(trim($try_file))).' ';
603 }
604 }
605 }
606 unset($try_file);
607 }
609 if(isset($this->scan_functions[$token_value])
610 && !(($this->tokens[$i + 1] === '(' && $this->tokens[$i + 2] === ')') || $this->tokens[$i + 1] === ';') //skip function with empty parameter list
611 )
612 {
613 //check if query function is NOT belong to CHTTP object
614 if (
615 $token_value === 'query'
616 && (is_array($this->tokens[$i-2]) && $this->tokens[$i-2][0] === T_VARIABLE)
617 && isset($this->objects[$this->tokens[$i-2][1]])
618 && $this->objects[$this->tokens[$i-2][1]] === 'CHTTP'
619 )
620 {
621 $result = false;
622 }
623 elseif($token_value !== 'query' && is_array($this->tokens[$i-1]) && in_array($this->tokens[$i-1][0], [T_PAAMAYIM_NEKUDOTAYIM, T_OBJECT_OPERATOR], true))
624 {
625 $result = false;
626 }
627 elseif($this->tokens[$i + 1] === '(')
628 {
629 $result = $this->getTokensInfo(array_slice($this->tokens, $i + 2, $this->getBraceEnd($this->tokens, $i + 2) - 1), false, $token_value);
630 }
631 else
632 {
633 $result = $this->getTokensInfo(array_slice($this->tokens, $i + 1, $this->getBraceEnd($this->tokens, $i + 1)), false, $token_value);
634 }
635
636 if($result !== false)
637 {
638 $tainted_vars = array();
639 foreach ($result[1] as $res)
640 {
641 if(!$res['secure'] && !isset($tainted_vars[$res['var_name']]))
642 {
643 if($res['requestInitialization'] || !array_key_exists($token_value, $this->vuln_func['XSS']))
644 {
645 $tainted_vars[$res['var_name']] = '<div class="checklist-vulnscan-code">';
646 $tainted_vars[$res['var_name']].= $this->traverseVar($res['var_name'], $i);
647 $tainted_vars[$res['var_name']].= '</div>';
648 $this->vuln_count++;
649 }
650 }
651 }
652
653 if(!empty($tainted_vars))
654 {
655 //little hack for $DB->Query, TODO: Fix this later!
656 if($token_value === 'query')
657 $pos = $i - 2;
658 else $pos = $i;
659
660 $vuln = new CVuln(
661 $this->scanning_file,
662 $cur_line,
663 $token_value,
664 array_slice($this->tokens, $pos, $this->getBraceEnd($this->tokens, $pos)),
665 $this->dependencies,
666 $tainted_vars,
667 $this->comment
668 );
669
670 $this->arResult[] = $vuln;
671 }
672
673 }
674 }
675 }
676 elseif(in_array($token, $this->tokens_type['FLOW_CONTROL']))
677 {
678 $c = 1;
679 while (($i + $c) < count($this->tokens) && $this->tokens[$i + $c] !== '{')
680 $c++;
681
682 $this->dependency = array_slice($this->tokens, $i, $c);
683 $this->dependency_line = $cur_line;
684 }
685 elseif($token === T_INCLUDE_END)
686 {
687 array_pop($this->file_history);
688 $this->current_file = & end($this->file_history);
689 $this->comment = basename($this->current_file) == basename($this->scanning_file) ? '' : basename($this->current_file);
690 }
691
692 //dependency check
693 if($token === T_EXIT && count($this->dependencies) === 1 && $this->dependencyHave(end($this->dependencies), '!XSS'))
694 $this->global_xss_ignore = true;
695
696 //end of dependency check
697 }
698 else
699 {
700 if($this->tokens[$i] === '{'
701 && ($this->tokens[$i - 1] === ')' || $this->tokens[$i - 1] === ':'
702 || (is_array($this->tokens[$i - 1]) && $this->tokens[$i - 1][0] === T_ELSE))
703 )
704 {
705 if(count($this->dependency) > 2
706 && $this->dependency[0][0] === T_ELSE && $this->dependency[1][0] !== T_IF
707 )
708 {
709 $this->dependency = $this->last_dependency;
710 $this->dependency[] = array(T_ELSE, 'else', $this->dependency[0][2]);
711 }
712 $this->dependencies[$this->dependency_line] = $this->dependency;
713
714 if($this->dependencyHave($this->dependency, 'XSS'))
715 $this->search_xss = false;
716
717 $this->dependency = array();
718 $this->dependency_line = 'syntax_error';
719 $this->braces++;
720 }
721 elseif($this->tokens[$i] === '}'
722 && ($this->tokens[$i - 1] === ';' || $this->tokens[$i - 1] === '}' || $this->tokens[$i - 1] === '{')
723 )
724 {
725 $this->braces--;
726
727 $this->last_dependency = array_pop($this->dependencies);
728
729 if($this->dependencyHave($this->last_dependency, 'XSS'))
730 $this->search_xss = true;
731
732 $this->dependency = array();
733 }
734 }
735 }
736 return true;
737 }
738
739 private static function tokenToString($token)
740 {
741 $result = '';
742 for ($i = 0, $count = count($token); $i < $count; $i++)
743 {
744 if(is_array($token[$i]))
745 $result .= self::tokenToString($token[$i]);
746 else
747 $result .= $token[$i][1];
748 }
749 return $result;
750 }
751
752 private function getClassName($token)
753 {
754 $className = '';
755 while(
756 is_array($this->tokens[$token])
757 && (
758 ($this->tokens[$token][0] === T_STRING)
759 || ($this->tokens[$token][0] === T_NS_SEPARATOR)
760 )
761 )
762 {
763 $className .= $this->tokens[$token][1];
764 $token++;
765 }
766 return $className;
767 }
768
769 private function getVarName($token, $level = -1)
770 {
771 $var_name = $token[1] ?? null;
772 if (isset($token[3]) && is_array($token[3]))
773 {
774 for ($i = 0, $count = count($token[3]); $i < $count && ($i < $level || $level === -1); $i++)
775 {
776 if(is_array($token[3][$i]))
777 {
778 /*
779 // TODO: to fix with foreach
780 $res=$this->getTokensInfo($token[3][$i], true);
781 if($res === false)
782 $var_name .='['.self::tokenToString($token[3][$i]).']';
783 */
784 }
785 else
786 {
787 $var_name .= '['.$token[3][$i].']';
788 }
789 }
790 }
791 return $var_name;
792 }
793
794 private function clearVariables($var)
795 {
796 $this->variables;
797 if(!empty($this->variables))
798 {
799 foreach (array_keys($this->variables) as $key)
800 {
801 if(preg_match('/'.preg_quote($var).'\[/is', $key))
802 unset($this->variables[$key]);
803 }
804 }
805
806 }
807
808 private function addVariable($var, $id, $line, $start, $end, $comment = '', $customTokens = array())
809 {
810
811 $tokens = !empty($customTokens) ? $customTokens : array_slice($this->tokens, $start, $end);
812 $tokensForScan = !empty($customTokens) ? $customTokens : array_slice($this->tokens, $start + 2, $end - 2);
813 $tokensInfo = $this->getTokensInfo($tokensForScan);
814
815 $dependencies = array();
816 /*TODO: Use dependency to detect overwritten variable!
817 * foreach ($this->dependencies as $dep_line => $dependency)
818 {
819 if(!empty($dependency))
820 $dependencies[$dep_line] = $dependency;
821 }*/
822
823 $varName = self::getVarName($var);
824 $this->clearVariables($varName);
825 if($tokensInfo !== false)
826 {
827 $taintedVars = array();
828 foreach ($tokensInfo[1] as $res)
829 $taintedVars[] = $res['var_name'] ?? null;
830
831 if(!isset($this->variables[$varName]))
832 $var = new CVariable($varName);
833 else
834 $var = $this->variables[$varName];
835
836 $var->have_user_input = true;
837 $var->secure = $tokensInfo[0];
838 $var->requestInitialization = $tokensInfo[2];
839 if (!$this->search_xss)
840 $var->requestInitialization = false;
841 $var->newDeclare($id, $line, $start, $end, $tokens, $this->comment.$comment, $dependencies, $taintedVars);
842 $this->variables[$varName] = $var;
843 }
844 elseif(isset($this->variables[$varName]))
845 {
846 unset($this->variables[$varName]); //TODO: Fix this, with dependency overwritten!
847 }
848 }
849
850 public function tokenize($code, $component_template = '')
851 {
852 if(preg_match_all('/\$GLOBALS\[\'[_0-9]*\'\]/', $code, $mat) > 20)
853 return array();
854 $tokens = token_get_all($code);
855 $tokens = $this->prepareTokens($tokens);
856 $tokens = $this->reconstructArray($tokens);
857 $tokens = $this->fixTokens($tokens, $component_template);
858 $tokens = $this->removeTernary($tokens);
859
860
861 return $tokens;
862 }
863
864 private function prepareTokens($tokens)
865 {
866 for ($i = 0, $c = count($tokens); $i < $c; $i++)
867 {
868 if(is_array($tokens[$i]))
869 {
870 if(in_array($tokens[$i][0], $this->tokens_type['IGNORE']))
871 unset($tokens[$i]);
872 elseif($tokens[$i][0] === T_CLOSE_TAG)
873 if(!isset($tokens[$i - 1]) || ($tokens[$i - 1] !== '{' && $tokens[$i - 1] !== ';'))
874 $tokens[$i] = ';'; else
875 unset($tokens[$i]);
876 elseif($tokens[$i][0] === T_OPEN_TAG_WITH_ECHO)
877 $tokens[$i][1] = 'echo';
878 elseif($tokens[$i][0] == T_CLASS)
879 {
880 unset($tokens[$i]);
881 $braces = 1;
882 $f = 1;
883 while ($tokens[$i + $f] !== '{' && ($i + $f) < $c)
884 {
885 unset($tokens[$i + $f]);
886 $f++;
887 }
888
889 $f++;
890 while ($braces !== 0 && ($i + $f) < $c)
891 {
892 if($tokens[$i + $f] === '{')
893 $braces++;
894 elseif($tokens[$i + $f] === '}')
895 $braces--;
896 unset($tokens[$i + $f]);
897 $f++;
898 }
899
900 for ($j = $i; $j < $i + $f + 1; $j++)
901 unset($tokens[$j]);
902 $i += $f;
903 }
904 elseif($tokens[$i][0] == T_FUNCTION)
905 {
906 unset($tokens[$i]);
907
908 if(is_array($tokens[$i + 1]) && $tokens[$i + 1][0] === T_STRING)
909 {
910 $this->sec_func['STRING'][] = strtolower($tokens[$i + 1][1]);
911 }
912 else
913 {
914 $f = 1;
915 while ($tokens[$i + $f] !== '(' && ($i + $f) < $c)
916 {
917 $f++;
918 }
919 if(isset($tokens[$i + $f - 1]) && is_array($tokens[$i + $f - 1]) && $tokens[$i + $f - 1][0] === T_STRING)
920 {
921 $this->sec_func['STRING'][] = strtolower($tokens[$i + $f - 1][1]);
922 }
923 }
924
925 $f = 1;
926 $braces = 1;
927 while (($i + $f) < $c && $tokens[$i + $f] !== '{')
928 {
929 unset($tokens[$i + $f]);
930 $f++;
931 }
932 $f++;
933 while ($braces !== 0 && ($i + $f) < $c)
934 {
935 if(isset($tokens[$i + $f]) && $tokens[$i + $f] === '{')
936 $braces++;
937 elseif(isset($tokens[$i + $f]) && $tokens[$i + $f] === '}')
938 $braces--;
939 unset($tokens[$i + $f]);
940 $f++;
941 }
942 for ($j = $i; $j < $i + $f + 1; $j++)
943 unset($tokens[$j]);
944 $i += $f;
945 }
946 }
947 elseif(isset($tokens[$i]) && $tokens[$i] === '@')
948 {
949 unset($tokens[$i]);
950 }
951 }
952
953 return array_values($tokens);
954 }
955
956 private function wrapBraces($tokens, $start, $between, $end)
957 {
958
959 $tokens = array_merge(
960 array_slice($tokens, 0, $start),
961 array('{'),
962 array_slice($tokens, $start, $between),
963 array('}'),
964 array_slice($tokens, $end)
965 );
966
967 return $tokens;
968 }
969
970 private function fixTokens($tokens, $component_template = '')
971 {
972 for ($i = 0, $max = count($tokens); $i < $max; $i++)
973 {
974 if($tokens[$i] === '`')
975 {
976 $f = 1;
977 while ($tokens[$i + $f] !== '`')
978 {
979 if(is_array($tokens[$i + $f]))
980 $line = $tokens[$i + $f][2];
981
982 $f++;
983 if(!isset($tokens[$i + $f]) || $tokens[$i + $f] === ';')
984 {
985 break;
986 }
987 }
988 if(!empty($line))
989 {
990 $tokens[$i + $f] = ')';
991 $tokens[$i] = array(T_STRING, 'backticks', $line);
992
993 $tokens = array_merge(
994 array_slice($tokens, 0, $i + 1), array('('), array_slice($tokens, $i + 1)
995 );
996 }
997 }
998 elseif(is_array($tokens[$i]))
999 {
1000 if(strtolower($tokens[$i][1]) === 'includecomponenttemplate' || strtolower($tokens[$i][1]) === 'initcomponenttemplate')
1001 {
1002 $tokens[$i][3] = $component_template;
1003 $tokens[$i][1] = strtolower($tokens[$i][1]);
1004 $tokens[$i][0] = T_INCLUDE_COMPONENTTEMPLATE;
1005 $tmp = array(array(T_INCLUDE_RESULT_MODIFIER, 'include_result_modifier', $tokens[$i][2], $component_template));
1006 array_splice($tokens, $i - 1, 0, $tmp);
1007 $i++;
1008 }
1009 elseif(strtolower($tokens[$i][1]) == 'includecomponent')
1010 {
1011 $tokens[$i][1] = strtolower($tokens[$i][1]);
1012 $tokens[$i][0] = T_INCLUDE_COMPONENT;
1013 }
1014 elseif(($tokens[$i][0] === T_IF || $tokens[$i][0] === T_ELSEIF || $tokens[$i][0] === T_FOR
1015 || $tokens[$i][0] === T_FOREACH || $tokens[$i][0] === T_WHILE) && $tokens[$i + 1] === '('
1016 )
1017 {
1018 $f = 2;
1019 $braceopen = 1;
1020 while ($braceopen !== 0 && ($i + $f) < $max)
1021 {
1022 if($tokens[$i + $f] === '(')
1023 $braceopen++;
1024 elseif($tokens[$i + $f] === ')')
1025 $braceopen--;
1026 $f++;
1027
1028 if(!isset($tokens[$i + $f]))
1029 {
1030 break;
1031 }
1032 }
1033
1034 if($tokens[$i + $f] === ':')
1035 {
1036 switch ($tokens[$i][0])
1037 {
1038 case T_IF:
1039 case T_ELSEIF:
1040 $endtoken = T_ENDIF;
1041 break;
1042 case T_FOR:
1043 $endtoken = T_ENDFOR;
1044 break;
1045 case T_FOREACH:
1046 $endtoken = T_ENDFOREACH;
1047 break;
1048 case T_WHILE:
1049 $endtoken = T_ENDWHILE;
1050 break;
1051 default:
1052 $endtoken = ';';
1053 }
1054
1055 $c = 1;
1056 while ($tokens[$i + $f + $c][0] !== $endtoken)
1057 {
1058 $c++;
1059 if(!isset($tokens[$i + $f + $c]))
1060 {
1061 break;
1062 }
1063 }
1064 $tokens = $this->wrapBraces($tokens, $i + $f + 1, $c + 1, $i + $f + $c + 2);
1065 }
1066 elseif($tokens[$i + $f] !== '{' && $tokens[$i + $f] !== ';')
1067 {
1068 $c = 1;
1069 while ($tokens[$i + $f + $c] !== ';' && $c < $max)
1070 {
1071 $c++;
1072 }
1073 $tokens = $this->wrapBraces($tokens, $i + $f, $c + 1, $i + $f + $c + 1);
1074 }
1075 }
1076 elseif($tokens[$i][0] === T_ELSE
1077 && $tokens[$i + 1][0] !== T_IF
1078 && $tokens[$i + 1] !== '{'
1079 )
1080 {
1081 $f = 2;
1082 while ($tokens[$i + $f] !== ';' && $f < $max)
1083 {
1084 $f++;
1085 }
1086 $tokens = $this->wrapBraces($tokens, $i + 1, $f, $i + $f + 1);
1087 }
1088 elseif($tokens[$i][0] === T_SWITCH && $tokens[$i + 1] === '(')
1089 {
1090 $braces = 1;
1091 $c = 2;
1092 while ($braces !== 0)
1093 {
1094 if($tokens[$i + $c] === '(')
1095 {
1096 $braces++;
1097 }
1098 elseif($tokens[$i + $c] === ')')
1099 {
1100 $braces--;
1101 }
1102 elseif(!isset($tokens[$i + $c]) || $tokens[$i + $c] === ';')
1103 {
1104 break;
1105 }
1106 $c++;
1107 }
1108 if($tokens[$i + $c] === ':')
1109 {
1110 $f = 1;
1111 while ($tokens[$i + $c + $f][0] !== T_ENDSWITCH)
1112 {
1113 $f++;
1114 if(!isset($tokens[$i + $c + $f]))
1115 break;
1116 }
1117 $tokens = $this->wrapBraces($tokens, $i + $c + 1, $f + 1, $i + $c + $f + 2);
1118 }
1119 }
1120 elseif($tokens[$i][0] === T_CASE)
1121 {
1122 $e = 1;
1123 while ($tokens[$i + $e] !== ':' && $tokens[$i + $e] !== ';')
1124 {
1125 $e++;
1126
1127 if(!isset($tokens[$i + $e]))
1128 break;
1129 }
1130 $f = $e + 1;
1131 if(($tokens[$i + $e] === ':' || $tokens[$i + $e] === ';')
1132 && $tokens[$i + $f] !== '{'
1133 && $tokens[$i + $f][0] !== T_CASE && $tokens[$i + $f][0] !== T_DEFAULT
1134 )
1135 {
1136 $braces = 0;
1137 while ($braces || (isset($tokens[$i + $f]) && $tokens[$i + $f] !== '}'
1138 && !(is_array($tokens[$i + $f])
1139 && ($tokens[$i + $f][0] === T_BREAK || $tokens[$i + $f][0] === T_CASE
1140 || $tokens[$i + $f][0] === T_DEFAULT || $tokens[$i + $f][0] === T_ENDSWITCH
1141 )
1142 )
1143 ))
1144 {
1145 if($tokens[$i + $f] === '{')
1146 $braces++;
1147 elseif($tokens[$i + $f] === '}')
1148 $braces--;
1149 $f++;
1150
1151 if(!isset($tokens[$i + $f]))
1152 break;
1153 }
1154 if($tokens[$i + $f][0] === T_BREAK)
1155 {
1156 if($tokens[$i + $f + 1] === ';')
1157 $tokens = $this->wrapBraces($tokens, $i + $e + 1, $f - $e + 1, $i + $f + 2);
1158 else
1159 $tokens = $this->wrapBraces($tokens, $i + $e + 1, $f - $e + 2, $i + $f + 3);
1160 }
1161 else
1162 {
1163 $tokens = $this->wrapBraces($tokens, $i + $e + 1, $f - $e - 1, $i + $f);
1164 }
1165 $i++;
1166 }
1167 }
1168 elseif($tokens[$i][0] === T_DEFAULT
1169 && $tokens[$i + 2] !== '{'
1170 )
1171 {
1172 $f = 2;
1173 $braces = 0;
1174 while ($tokens[$i + $f] !== ';' && $tokens[$i + $f] !== '}' || $braces)
1175 {
1176 if($tokens[$i + $f] === '{')
1177 $braces++;
1178 elseif($tokens[$i + $f] === '}')
1179 $braces--;
1180 $f++;
1181
1182 if(!isset($tokens[$i + $f]))
1183 break;
1184 }
1185 $tokens = $this->wrapBraces($tokens, $i + 2, $f - 1, $i + $f + 1);
1186 }
1187 elseif($tokens[$i][0] === T_FUNCTION)
1188 {
1189 $tokens[$i + 1][1] = strtolower($tokens[$i + 1][1]);
1190 }
1191 elseif($tokens[$i][0] === T_STRING && $tokens[$i + 1] === '(')
1192 {
1193 $tokens[$i][1] = strtolower($tokens[$i][1]);
1194 }
1195 elseif($tokens[$i][0] === T_DO)
1196 {
1197 $f = 2;
1198 $otherDOs = 0;
1199 while ($tokens[$i + $f][0] !== T_WHILE || $otherDOs)
1200 {
1201 if($tokens[$i + $f][0] === T_DO)
1202 $otherDOs++;
1203 elseif($tokens[$i + $f][0] === T_WHILE)
1204 $otherDOs--;
1205 $f++;
1206
1207 if(!isset($tokens[$i + $f]))
1208 break;
1209 }
1210
1211 if($tokens[$i + 1] !== '{')
1212 {
1213 $tokens = $this->wrapBraces($tokens, $i + 1, $f - 1, $i + $f);
1214 $f += 2;
1215 }
1216
1217 $d = 1;
1218 while ($tokens[$i + $f + $d] !== ';' && $d < $max)
1219 {
1220 $d++;
1221 }
1222
1223 $tokens = array_merge(
1224 array_slice($tokens, 0, $i),
1225 array_slice($tokens, $i + $f, $d),
1226 array_slice($tokens, $i + 1, $f - 1),
1227 array_slice($tokens, $i + $f + $d + 1, count($tokens))
1228 );
1229 }
1230 }
1231 }
1232 return array_values($tokens);
1233 }
1234
1235 private function reconstructArray($tokens)
1236 {
1237 for ($i = 0, $max = count($tokens); $i < $max; $i++)
1238 {
1239 if(is_array($tokens[$i]) && $tokens[$i][0] === T_VARIABLE && $tokens[$i + 1] === '[')
1240 {
1241 $tokens[$i][3] = array();
1242 $has_more_keys = true;
1243 $index = -1;
1244 $c = 2;
1245
1246 while ($has_more_keys && $index < 20)
1247 {
1248 $index++;
1249 if(($tokens[$i + $c][0] === T_CONSTANT_ENCAPSED_STRING || $tokens[$i + $c][0] === T_LNUMBER || $tokens[$i + $c][0] === T_NUM_STRING) && $tokens[$i + $c + 1] === ']')
1250 {
1251 unset($tokens[$i + $c - 1]);
1252 $tokens[$i][3][$index] = str_replace(array('"', "'"), '', $tokens[$i + $c][1]);
1253 unset($tokens[$i + $c]);
1254 unset($tokens[$i + $c + 1]);
1255 $c += 2;
1256 }
1257 else
1258 {
1259 $tokens[$i][3][$index] = array();
1260 $braces = 1;
1261 unset($tokens[$i + $c - 1]);
1262 while ($braces !== 0 && $c < 100)
1263 {
1264 if($tokens[$i + $c] === '[')
1265 {
1266 $braces++;
1267 }
1268 elseif($tokens[$i + $c] === ']')
1269 {
1270 $braces--;
1271 }
1272 else
1273 {
1274 $tokens[$i][3][$index][] = $tokens[$i + $c];
1275 }
1276 unset($tokens[$i + $c]);
1277 $c++;
1278 }
1279 unset($tokens[$i + $c - 1]);
1280 }
1281 if($tokens[$i + $c] !== '[')
1282 $has_more_keys = false;
1283 $c++;
1284 }
1285
1286 $i += $c - 1;
1287 }
1288 }
1289
1290 return array_values($tokens);
1291 }
1292
1293 private function removeTernary($tokens)
1294 {
1295 $max = count($tokens);
1296 $i = 0;
1297
1298 while ($i < $max)
1299 {
1300 if($tokens[$i] === '?')
1301 {
1302 unset($tokens[$i]);
1303
1304 $k = 1;
1305 $braces = 0;
1306 while (!(isset($tokens[$i - $k]) && ($tokens[$i - $k] === ';' || $tokens[$i - $k] === ', ' || $tokens[$i - $k] === '.' || $tokens[$i - $k] === '{' || $tokens[$i - $k] === '}') && $braces <= 0) && ($i - $k) > 0)
1307 {
1308 if(isset($tokens[$i - $k]) && $tokens[$i - $k] === ')')
1309 $braces++;
1310 elseif(isset($tokens[$i - $k]) && $tokens[$i - $k] === '(')
1311 $braces--;
1312 unset($tokens[$i - $k]);
1313 $k++;
1314 }
1315
1316 $k = 1;
1317 $braces = 0;
1318 while (!(isset($tokens[$i + $k]) && ($tokens[$i + $k] === ';' || $tokens[$i + $k] === ', ' || $tokens[$i + $k] === '.' || $tokens[$i + $k] === '}') && $braces <= 0) && ($i + $k) < $max)
1319 {
1320 if(isset($tokens[$i + $k]) && $tokens[$i + $k] === '(')
1321 $braces++;
1322 elseif(isset($tokens[$i + $k]) && $tokens[$i + $k] === ')')
1323 $braces--;
1324 unset($tokens[$i + $k]);
1325 $k++;
1326 }
1327 $i += $k;
1328 }
1329 $i++;
1330 }
1331
1332 return array_values($tokens);
1333 }
1334
1335 private function getTokensValue($file_name, $tokens, $start = 0, $stop = 0)
1336 {
1337 $value = '';
1338 if(!$stop)
1339 $stop = count($tokens);
1340 for ($i = $start; $i < $stop; $i++)
1341 {
1342 if(is_array($tokens[$i]))
1343 {
1344 if($tokens[$i][0] === T_VARIABLE
1345 || ($tokens[$i][0] === T_STRING
1346 && ($i + 1) < $stop && $tokens[$i + 1] !== '(')
1347 )
1348 {
1349 if(!in_array($tokens[$i][1], $this->v_userinput))
1350 {
1351 if($tokens[$i][1] === 'DIRECTORY_SEPARATOR' || $tokens[$i][1] === 'PATH_SEPARATOR')
1352 $value .= '/';
1353 elseif(strtolower($tokens[$i][1]) === '$componentpath')
1354 $value = dirname($file_name);
1355 elseif($tokens[$i][1] === '$_SERVER' && $tokens[$i][3][0] === 'DOCUMENT_ROOT')
1356 $value .= $this->arParams['doc_root_path'];
1357 }
1358 }
1359 elseif($tokens[$i][0] === T_CONSTANT_ENCAPSED_STRING
1360 )
1361 {
1362
1363 $value .= substr($tokens[$i][1], 1, -1);
1364 }
1365 elseif($tokens[$i][0] === T_ENCAPSED_AND_WHITESPACE)
1366 {
1367 $value .= $tokens[$i][1];
1368 }
1369 elseif($tokens[$i][0] === T_FILE
1370 && ($i > 2 && $tokens[$i - 2][0] === T_STRING && $tokens[$i - 2][1] === 'dirname')
1371 )
1372 {
1373 $value = dirname($file_name).'/';
1374 }
1375 elseif($tokens[$i][0] === T_LNUMBER || $tokens[$i][0] === T_DNUMBER || $tokens[$i][0] === T_NUM_STRING)
1376 {
1377 $value .= round($tokens[$i][1]);
1378 }
1379 elseif($tokens[$i][0] === T_AS)
1380 {
1381 break;
1382 }
1383 }
1384 }
1385
1386 return $value;
1387 }
1388
1389 private function getBraceEnd($tokens, $i)
1390 {
1391 $c = 1;
1392 $braces = 1;
1393 $max=count($tokens);
1394 while (!($braces === 0 || $tokens[$i + $c] === ';'))
1395 {
1396 if($tokens[$i + $c] === '(')
1397 {
1398 $braces++;
1399 }
1400 elseif($tokens[$i + $c] === ')')
1401 {
1402 $braces--;
1403 }
1404 if($c > 50 || $c > $max)
1405 break;
1406 $c++;
1407 }
1408 return $c;
1409 }
1410
1411 private function getColor($token)
1412 {
1413 if(array_key_exists($token, $this->color))
1414 return $this->color[$token];
1415 else
1416 return '#007700';
1417 }
1418
1419 private function highlightArray($token)
1420 {
1421 $result = '';
1422 foreach ($token as $key)
1423 {
1424 if($key != '*')
1425 {
1426 $result .= '<span style="color: #007700;">[</span>';
1427 if(!is_array($key))
1428 {
1429 if(is_numeric($key))
1430 $result .= '<span style="color: #0000BB;">'.$key.'</span>';
1431 else
1432 $result .= '<span style="color: #DD0000;">\''.htmlentities($key, ENT_QUOTES, 'utf-8').'\'</span>';
1433 }
1434 else
1435 {
1436 foreach ($key as $token)
1437 {
1438 if(is_array($token))
1439 {
1440 if(isset($token[3]))
1441 $result .= $this->highlightArray($token[3]);
1442 else
1443 $result .= '<span style="color: '.$this->getColor($token[0]).';">'.htmlentities($token[1], ENT_QUOTES, 'utf-8').'</span>';
1444 }
1445 else
1446 $result .= "<span style=\"color: #007700;\">{$token}</span>";
1447 }
1448 }
1449 $result .= '<span style="color: #007700;">]</span>';
1450 }
1451 }
1452 return $result;
1453 }
1454
1455 private function highlightLine($line, $tokens = array(), $tainted_vars = array(), $comment = '')
1456 {
1457 $output = '';
1458 for ($i = 0, $count = count($tainted_vars); $i < $count; $i++)
1459 {
1460 if($pos = strpos($tainted_vars[$i], '['))
1461 $tainted_vars[$i] = substr($tainted_vars[$i], 0, $pos);
1462 }
1463 if(isset($line))
1464 $output .= "<span>$line:</span>&nbsp;";
1465
1466 for ($i = 0, $count = count($tokens); $i < $count; $i++)
1467 {
1468 $token = $tokens[$i];
1469 if(is_string($token))
1470 {
1471 if($token === ', ' || $token === ';')
1472 $output .= "<span style=\"color: #007700;\">$token&nbsp;</span>";
1473 elseif(in_array($token, $this->tokens_type['SPACE_WRAP_STR']) || in_array($token, $this->tokens_type['ARITHMETIC_STR']))
1474 $output .= '<span style="color: #007700;">&nbsp;'.$token.'&nbsp;</span>';
1475 else
1476 $output .= '<span style="color: #007700;">'.htmlentities($token, ENT_QUOTES, 'utf-8').'</span>';
1477 }
1478 elseif(is_array($token)
1479 && $token[0] !== T_OPEN_TAG
1480 && $token[0] !== T_CLOSE_TAG
1481 )
1482 {
1483
1484 if(in_array($token[0], $this->tokens_type['SPACE_WRAP']) || in_array($token[0], $this->tokens_type['OPERATOR']) || in_array($token[0], $this->tokens_type['ASSIGNMENT']))
1485 {
1486 $output .= '&nbsp;<span style="color: '.$this->getColor($token[0]).";\">{$token[1]}</span>&nbsp;";
1487 }
1488 else
1489 {
1490 $text = htmlentities($token[1], ENT_QUOTES, 'utf-8');
1491 $text = str_replace(array(' ', "\n"), '&nbsp;', $text);
1492
1493 if($token[0] === T_FUNCTION)
1494 $text .= '&nbsp;';
1495
1496 $span = "<span ";
1497
1498 if($token[0] === T_VARIABLE && is_array($tainted_vars) && in_array($token[1], $tainted_vars))
1499 $span .= "style=\"color: #0000BB;\"><b>".$text."</b></span>";
1500 else
1501 $span .= "style=\"color: ".$this->getColor($token[0]).";\">$text</span>";
1502
1503 $text = $span;
1504
1505 if(isset($token[3]))
1506 {
1507 $text .= $this->highlightArray($token[3]);
1508 }
1509
1510 $output .= $text;
1511 if(in_array($token[0], $this->tokens_type['INCLUDES']) || in_array($token[0], $this->tokens_type['XSS']) || $token[0] === 'T_EVAL')
1512 {
1513 $output .= '&nbsp;';
1514 }
1515 }
1516 }
1517 }
1518
1519 if(!empty($comment))
1520 {
1521 $output .= '&nbsp;<span style="color: #808080;">// '.htmlentities($comment, ENT_QUOTES, 'utf-8').'</span>';
1522 }
1523
1524 return '<div style="clear:both;">'.$output.'</div>';
1525 }
1526
1527 private function getVulnNodeTitle($func_name)
1528 {
1529 if(isset($this->vuln_func['XSS'][$func_name]))
1530 $vulnname = GetMessage('VULNSCAN_XSS_NAME');
1531 elseif(isset($this->vuln_func['HTTP_HEADER'][$func_name]))
1532 $vulnname = GetMessage('VULNSCAN_HEADER_NAME');
1533 elseif(isset($this->vuln_func['DATABASE'][$func_name]))
1534 $vulnname = GetMessage('VULNSCAN_DATABASE_NAME');
1535 elseif(isset($this->vuln_func['FILE_INCLUDE'][$func_name]))
1536 $vulnname = GetMessage('VULNSCAN_INCLUDE_NAME');
1537 elseif(isset($this->vuln_func['EXEC'][$func_name]))
1538 $vulnname = GetMessage('VULNSCAN_EXEC_NAME');
1539 elseif(isset($this->vuln_func['CODE'][$func_name]))
1540 $vulnname = GetMessage('VULNSCAN_CODE_NAME');
1541 elseif(isset($this->vuln_func['POP'][$func_name]))
1542 $vulnname = GetMessage('VULNSCAN_POP_NAME');
1543 elseif(isset($this->vuln_func['OTHER'][$func_name]))
1544 $vulnname = GetMessage('VULNSCAN_OTHER_NAME');
1545 else
1546 $vulnname = GetMessage('VULNSCAN_UNKNOWN');
1547
1548 return $vulnname;
1549 }
1550
1551 private function getVulnNodeDescription($func_name)
1552 {
1553 if(isset($this->vuln_func['XSS'][$func_name]))
1554 $vulnhelp = GetMessage('VULNSCAN_XSS_HELP');
1555 elseif(isset($this->vuln_func['HTTP_HEADER'][$func_name]))
1556 $vulnhelp = GetMessage('VULNSCAN_HEADER_HELP');
1557 elseif(isset($this->vuln_func['DATABASE'][$func_name]))
1558 $vulnhelp = GetMessage('VULNSCAN_DATABASE_HELP');
1559 elseif(isset($this->vuln_func['FILE_INCLUDE'][$func_name]))
1560 $vulnhelp = GetMessage('VULNSCAN_INCLUDE_HELP');
1561 elseif(isset($this->vuln_func['EXEC'][$func_name]))
1562 $vulnhelp = GetMessage('VULNSCAN_EXEC_HELP');
1563 elseif(isset($this->vuln_func['CODE'][$func_name]))
1564 $vulnhelp = GetMessage('VULNSCAN_CODE_HELP');
1565 elseif(isset($this->vuln_func['POP'][$func_name]))
1566 $vulnhelp = GetMessage('VULNSCAN_POP_HELP');
1567 elseif(isset($this->vuln_func['OTHER'][$func_name]))
1568 $vulnhelp = GetMessage('VULNSCAN_OTHER_HELP');
1569 else
1570 $vulnhelp = GetMessage('VULNSCAN_UNKNOWN_HELP');
1571
1572 return $vulnhelp;
1573 }
1574
1575 private function getVulnName($func_name)
1576 {
1577 if (isset($this->vuln_func['XSS'][$func_name]))
1578 return 'XSS';
1579 elseif (isset($this->vuln_func['HTTP_HEADER'][$func_name]))
1580 return 'HEADER';
1581 elseif (isset($this->vuln_func['DATABASE'][$func_name]))
1582 return 'DATABASE';
1583 elseif (isset($this->vuln_func['FILE_INCLUDE'][$func_name]))
1584 return 'INCLUDE';
1585 elseif (isset($this->vuln_func['EXEC'][$func_name]))
1586 return 'EXEC';
1587 elseif (isset($this->vuln_func['CODE'][$func_name]))
1588 return 'CODE';
1589 elseif (isset($this->vuln_func['POP'][$func_name]))
1590 return 'POP';
1591 elseif (isset($this->vuln_func['OTHER'][$func_name]))
1592 return 'OTHER';
1593 else
1594 return 'UNKNOWN';
1595 }
1596
1597 private function traverseVar($var, $id = -1)
1598 {
1599 $result = '';
1600 if(isset($this->variables[$var]))
1601 {
1602 $cur_var = $this->variables[$var];
1603 foreach ($cur_var->declares as $var_declare)
1604 {
1605 if($var_declare->id < $id || $id === -1)
1606 {
1607 foreach ($var_declare->tainted_vars as $taint_var)
1608 {
1609 $res = $this->traverseVar($taint_var, $var_declare->id);
1610 if($res && !str_contains($result, $res))
1611 $result .= $res;
1612 }
1613
1614 $result .= '<div class="checklist-vulnscan-code-line">';
1615 $result .= $this->highlightLine($var_declare->line, $var_declare->tokens, $var_declare->tainted_vars, $var_declare->comment);
1616 $result .= '</div>';
1617 }
1618 }
1619 }
1620 return $result;
1621 }
1622
1623 private function dependenciesTraverse($dependencies = array())
1624 {
1625 $result = '';
1626 if(!empty($dependencies))
1627 {
1628 $result .= GetMessage('VULNSCAN_REQUIRE').':';
1629
1630 foreach ($dependencies as $line => $dependency)
1631 {
1632 if(!empty($dependency))
1633 {
1634 $result .= $this->highlightLine($line, $dependency);
1635 }
1636 }
1637 }
1638 return $result;
1639 }
1640
1641 private static function searchSimilarVuln($output, $max)
1642 {
1643 for ($i = 0; $i < $max; $i++)
1644 {
1645 if(($output[$i]->name === $output[$max]->name) && ($output[$i]->filename === $output[$max]->filename) && $output[$i]->tainted_vars === $output[$max]->tainted_vars)
1646 return $i;
1647 }
1648 return false;
1649 }
1650
1651 private function prepareOutput($output)
1652 {
1653
1654 for ($i = 0, $count = count($output); $i < $count; $i++)
1655 {
1656 if(($find = self::searchSimilarVuln($output, $i)) !== false)
1657 {
1658 $output[$find]->additional_text .= '<div class="checklist-vulnscan-dangerous-is-here">';
1659 $output[$find]->additional_text .= $this->highlightLine($output[$i]->line, $output[$i]->tokens, $output[$i]->tainted_vars, $output[$i]->comment);
1660 $output[$find]->additional_text .= '</div>';
1661 unset($output[$i]);
1662 }
1663 }
1664 return $output;
1665 }
1666
1667 private function getHelp($category)
1668 {
1669 $result = '';
1670 /*
1671 $result = '<div class="checklist-vulnscan-helpbox-sheme">';
1672 $result .= '<table>';
1673 $result .= '<tr><td>'.GetMessage('VULNSCAN_HELP_INPUT').'</td><td>'.GetMessage('VULNSCAN_HELP_FUNCTION').'</td><td>'.GetMessage('VULNSCAN_HELP_VULNTYPE').'</td></tr>';
1674 $result .= '<tr><td>';
1675
1676 if (!empty($tree->source))
1677 $result .= $tree->source;
1678 else
1679 $result .= '$_GET';
1680
1681 $result .= '</td><td>';
1682 $result .= $tree->name.'()';
1683 $result .= '</td><td>';
1684 $result .= $this->getVulnNodeTitle($category);
1685 $result .= '</td></tr>';
1686 $result .= '</table></div>';*/
1687 $result .= '<div class="checklist-vulnscan-helpbox-description">';
1688 $result .= GetMessage('VULNSCAN_'.$this->getVulnName($category).'_HELP');
1689 $result .= '</div>';
1690 $result .= '<div class="checklist-vulnscan-helpbox-safe-title">';
1691 $result .= GetMessage('VULNSCAN_HELP_SAFE');
1692 $result .= '</div>';
1693 $result .= '<div class="checklist-vulnscan-helpbox-safe-description">';
1694 $result .= GetMessage('VULNSCAN_'.$this->getVulnName($category).'_HELP_SAFE');
1695 $result .= '</div>';
1696 return $result;
1697 }
1698
1699
1700 public function getOutput()
1701 {
1702 $output = $this->prepareOutput($this->arResult);
1703 $result = '';
1704 if(!empty($output))
1705 {
1706 foreach ($output as $vuln)
1707 {
1708
1709 $filename = htmlspecialcharsbx(str_replace(realpath(trim($this->arParams['doc_root_path'])), '',str_replace(realpath(trim($this->arParams['path'])), '', realpath(trim($vuln->filename)))));
1710
1711 foreach ($vuln->tainted_vars as $tainted_var_name => $tainted_var)
1712 {
1713 $result .= '<div class="checklist-dot-line"></div><div class="checklist-vulnscan-files">'.'<span class="checklist-vulnscan-filename">'.GetMessage('VULNSCAN_FILE').': '.$filename.'</span>'.'<div id="'.$filename.'">';
1714 $result .= '<div class="checklist-vulnscan-vulnblock">'.'<div class="checklist-vulnscan-vulnscan-blocktitle">'.GetMessage('VULNSCAN_'.$this->getVulnName($vuln->name).'_NAME').'</div>';
1715 $result .= '<div style="visibility: hidden; display:none;" class="checklist-vulnscan-helpbox" data-help="'.$filename.'">'.$this->getHelp($vuln->name).'</div>';
1716 $result .= $tainted_var;
1717
1718 $result .= '<div class="checklist-vulnscan-dangerous-is-here">';
1719 $result .= $this->highlightLine($vuln->line, $vuln->tokens, array($tainted_var_name), $vuln->comment);
1720 $result .= '</div>';
1721
1722 $result .= '<div class="checklist-vulnscan-dependecies">';
1723 $result .= $this->dependenciesTraverse($vuln->dependencies);
1724 $result .= '</div>';
1725
1726 if(!empty($vuln->additional_text))
1727 $result .= "\n".'<div><div class="checklist-vulnscan-vulnblocktitle">'.GetMessage('VULNSCAN_SIMILAR').':</div><div class="checklist-vulnscan-codebox"><div class="checklist-vulnscan-code">'.$vuln->additional_text.'</div></div></div>';
1728
1729
1730 $result .= '</div></div></div>';
1731 }
1732 }
1733 }
1734 return $result;
1735 }
1736}
1737
1739{
1740 static private function getFiles($path, $skip_preg, $file_types, $doc_root, &$files, &$dirs)
1741 {
1742 $handle = opendir($path);
1743 if ($handle)
1744 {
1745 while (($file = readdir($handle)) !== false)
1746 {
1747 if($file === '.' || $file === '..')
1748 continue;
1749
1750 $name = $path.'/'.str_replace("\\", "/", $file);
1751 if (preg_match($skip_preg, str_replace($doc_root, "", $name)))
1752 {
1753 continue;
1754 }
1755
1756 if (is_dir($name))
1757 {
1758 $dirs[] = $name;
1759 }
1760 elseif(in_array(substr($name, -4), $file_types))
1761 {
1762 $files[] = $name;
1763 }
1764 }
1765 }
1766 closedir($handle);
1767 }
1768
1769 static private function defineScanParams()
1770 {
1771 if(!defined('T_INCLUDE_RESULT_MODIFIER'))
1772 define('T_INCLUDE_RESULT_MODIFIER', 10001);
1773 if(!defined('T_INCLUDE_COMPONENTTEMPLATE'))
1774 define('T_INCLUDE_COMPONENTTEMPLATE', 10002);
1775 if(!defined('T_INCLUDE_COMPONENT'))
1776 define('T_INCLUDE_COMPONENT', 10003);
1777 if(!defined('T_INCLUDE_END'))
1778 define('T_INCLUDE_END', 10004);
1779 $SKIPDIR = array(// skipping directories
1780 'lang',
1781 'help',
1782 'images',
1783 'upload',
1784 'uploads',
1785 'jquery',
1786 'js',
1787 'css',
1788 '\/bitrix\/[^t].*',
1789 );
1790
1791 $SKIPFILE = array(// skipping files
1792 '\.access\.php',
1793 '\.description\.php',
1794 '\.parameters\.php',
1795 'install\/[\w]*\.php',
1796 );
1797
1798 $arResult = Array(
1799 'FILE_TYPES' => Array(
1800 '.php',
1801 '.inc'
1802 ),
1803 'PREG_FOR_SKIP_INCLUDE' => '/\/modules\/(bitrix\.)?[^\W\.]+\//is',
1804 'PREG_FOR_SKIP_SCAN' => '/(\/bitrix\/modules\/)|(\/bitrix\/components\/bitrix\/)|('.implode('$)|(', $SKIPDIR).'$)|('.implode('$)|(', $SKIPFILE).'$)/is',
1805 // 'VERBOSITY' => 1,
1806 'MAX_TRACE' => 30,
1807 'MAX_ARRAY_ELEMENTS' => 50,
1808 'MP_mode' => false,
1809 'production_mode' => false,
1810 'path' => $_SERVER['DOCUMENT_ROOT'],
1811 'doc_root_path' => $_SERVER['DOCUMENT_ROOT']
1812 );
1813
1814 $arResult['TOKENS_TYPES'] = Array(
1815 'IGNORE' => Array(
1816 T_BAD_CHARACTER,
1817 T_DOC_COMMENT,
1818 T_COMMENT,
1819 T_INLINE_HTML,
1820 T_WHITESPACE,
1821 T_OPEN_TAG
1822 ),
1823 'LOOP_CONTROL' => Array(
1824 T_WHILE,
1825 T_FOR,
1826 T_FOREACH
1827 ),
1828 'FLOW_CONTROL' => Array(
1829 T_IF,
1830 T_SWITCH,
1831 T_CASE,
1832 T_ELSE,
1833 T_ELSEIF
1834 ),
1835 'ASSIGNMENT' => Array(
1836 T_AND_EQUAL,
1837 T_CONCAT_EQUAL,
1838 T_DIV_EQUAL,
1839 T_MINUS_EQUAL,
1840 T_MOD_EQUAL,
1841 T_MUL_EQUAL,
1842 T_OR_EQUAL,
1843 T_PLUS_EQUAL,
1844 T_SL_EQUAL,
1845 T_SR_EQUAL,
1846 T_XOR_EQUAL
1847 ),
1848 'ASSIGNMENT_SECURE' => Array(
1849 T_DIV_EQUAL,
1850 T_MINUS_EQUAL,
1851 T_MOD_EQUAL,
1852 T_MUL_EQUAL,
1853 T_OR_EQUAL,
1854 T_PLUS_EQUAL,
1855 T_SL_EQUAL,
1856 T_SR_EQUAL,
1857 T_XOR_EQUAL
1858 ),
1859 'OPERATOR' => Array(
1860 T_IS_EQUAL,
1861 T_IS_GREATER_OR_EQUAL,
1862 T_IS_IDENTICAL,
1863 T_IS_NOT_EQUAL,
1864 T_IS_NOT_IDENTICAL,
1865 T_IS_SMALLER_OR_EQUAL
1866 ),
1867 'FUNCTIONS' => Array(
1868 T_STRING, // all functions
1869 T_EVAL
1870 ),
1871 'INCLUDES' => Array(
1872 T_INCLUDE,
1873 T_INCLUDE_ONCE,
1874 T_REQUIRE,
1875 T_REQUIRE_ONCE,
1876 T_INCLUDE_COMPONENT,
1877 T_INCLUDE_COMPONENTTEMPLATE,
1878 T_INCLUDE_RESULT_MODIFIER
1879 ),
1880 'XSS' => Array(
1881 T_PRINT,
1882 T_ECHO,
1883 T_OPEN_TAG_WITH_ECHO,
1884 T_EXIT
1885 ),
1886 'CASTS' => Array(
1887 T_BOOL_CAST,
1888 T_DOUBLE_CAST,
1889 T_INT_CAST,
1890 T_UNSET_CAST,
1891 T_UNSET
1892 ),
1893 'LOGICAL' => Array(
1894 T_BOOLEAN_AND,
1895 T_BOOLEAN_OR,
1896 T_LOGICAL_AND,
1897 T_LOGICAL_OR,
1898 T_LOGICAL_XOR
1899 ),
1900 'SPACE_WRAP' => Array(
1901 T_AS,
1902 T_BOOLEAN_AND,
1903 T_BOOLEAN_OR,
1904 T_LOGICAL_AND,
1905 T_LOGICAL_OR,
1906 T_LOGICAL_XOR,
1907 T_SL,
1908 T_SR,
1909 T_CASE,
1910 T_ELSE,
1911 T_GLOBAL,
1912 T_NEW
1913 ),
1914 'ARITHMETIC' => Array(
1915 T_INC,
1916 T_DEC
1917 ),
1918 'ARITHMETIC_STR' => Array(
1919 '+',
1920 '-',
1921 '*',
1922 '/',
1923 '%'
1924 ),
1925 'SPACE_WRAP_STR' => Array(
1926 '.',
1927 '=',
1928 '>',
1929 '<',
1930 ':',
1931 '?'
1932 )
1933 );
1934 $arResult['SECURING_FUNCTIONS'] = Array(
1935 'BOOL' => Array(
1936 'is_double',
1937 'is_float',
1938 'is_real',
1939 'is_long',
1940 'is_int',
1941 'is_integer',
1942 'ctype_alnum',
1943 'ctype_alpha',
1944 'ctype_cntrl',
1945 'ctype_digit',
1946 'ctype_xdigit',
1947 'ctype_upper',
1948 'ctype_lower',
1949 'ctype_space',
1950 'in_array',
1951 'preg_match',
1952 'preg_match_all',
1953 'fnmatch',
1954 'ereg',
1955 'eregi',
1956 ),
1957 'STRING' => Array(
1958 'intval',
1959 'floatval',
1960 'doubleval',
1961 'filter_input',
1962 'urlencode',
1963 'rawurlencode',
1964 'round',
1965 'floor',
1966 'strlen',
1967 'hexdec',
1968 'strrpos',
1969 'strpos',
1970 'md5',
1971 'sha1',
1972 'crypt',
1973 'crc32',
1974 'base64_encode',
1975 'ord',
1976 'sizeof',
1977 'count',
1978 'bin2hex',
1979 'levenshtein',
1980 'abs',
1981 'bindec',
1982 'decbin',
1983 'hexdec',
1984 'rand',
1985 'max',
1986 'min',
1987 'preg_replace', //Fix this later
1988 'getimagesize',
1989 'phpformatdatetime',
1990 'mkdatetime',
1991 'formatdateex',
1992 ),
1993 'INSTRING' => Array(
1994 'rawurldecode',
1995 'urldecode',
1996 'base64_decode',
1997 'html_entity_decode',
1998 'str_rot13',
1999 'chr',
2000 'htmlspecialcharsback',
2001 ),
2002 'XSS' => Array(
2003 'htmlentities',
2004 'htmlspecialchars',
2005 'htmlspecialcharsex',
2006 'htmlspecialcharsbx',
2007 'jsescape',
2008 'jsurlescape',
2009 'phptojsobject',
2010 'showerror',
2011 'showmessage',
2012 'showimage',
2013 'shownote',
2014 'getcurpageparam',
2015 'selectbox',
2016 'selectboxm',
2017 'selectboxfromarray',
2018 'getmessage',
2019 'getvars',
2020 'highlight_string',
2021 'inputtype',
2022 'inputtags',
2023 ),
2024 'SQL' => Array(
2025 'addslashes',
2026 'mysql_real_escape_string',
2027 'forsql',
2028 ),
2029 'PREG' => Array(
2030 'preg_quote'
2031 ),
2032 'FILE' => Array(
2033 'rel2abs'
2034 ),
2035 'SYSTEM' => Array(
2036 'escapeshellarg',
2037 'escapeshellcmd',
2038 ),
2039 'XPATH' => Array(
2040 'addslashes'
2041 )
2042 );
2043
2044 $arResult['SECURING_FUNCTIONS']['QUOTE_ANALYSIS'] = Array($arResult['SECURING_FUNCTIONS']['SQL']);
2045 $arResult['SECURING_FUNCTIONS']['SECURES_ALL'] = array_merge(
2046 $arResult['SECURING_FUNCTIONS']['XSS'],
2047 $arResult['SECURING_FUNCTIONS']['SQL'],
2048 $arResult['SECURING_FUNCTIONS']['PREG'],
2049 $arResult['SECURING_FUNCTIONS']['FILE'],
2050 $arResult['SECURING_FUNCTIONS']['SYSTEM'],
2051 $arResult['SECURING_FUNCTIONS']['XPATH']
2052 );
2053
2054 $arResult['VULN_FUNCTIONS'] = Array(
2055 'XSS' => Array(
2056 'echo' => array(0, $arResult['SECURING_FUNCTIONS']['XSS']),
2057 'print' => array(array(1), $arResult['SECURING_FUNCTIONS']['XSS']),
2058 'exit' => array(array(1), $arResult['SECURING_FUNCTIONS']['XSS']),
2059 'die' => array(array(1), $arResult['SECURING_FUNCTIONS']['XSS']),
2060 ),
2061 'HTTP_HEADER' => Array(
2062 'header' => array(array(1), array())
2063 ),
2064 'CODE' => Array(
2065 'assert' => Array(Array(1), Array()),
2066 'call_user_func' => Array(Array(1), Array()),
2067 'call_user_func_Array' => Array(Array(1), Array()),
2068 'create_function' => Array(Array(1, 2), Array()),
2069 'eval' => Array(Array(1), Array()),
2070 'mb_ereg_replace' => Array(Array(1, 2), $arResult['SECURING_FUNCTIONS']['PREG']),
2071 'mb_eregi_replace' => Array(Array(1, 2), $arResult['SECURING_FUNCTIONS']['PREG']),
2072 'ob_start' => Array(Array(1), Array()),
2073 //'preg_replace' => Array(Array(1, 2), $arResult['SECURING_FUNCTIONS']['PREG']),
2074 //'preg_replace_callback' => Array(Array(1, 2), $arResult['SECURING_FUNCTIONS']['PREG']),
2075 ),
2076 'FILE_INCLUDE' => Array(
2077 'include' => Array(Array(1), $arResult['SECURING_FUNCTIONS']['FILE']),
2078 'include_once' => Array(Array(1), $arResult['SECURING_FUNCTIONS']['FILE']),
2079 'require' => Array(Array(1), $arResult['SECURING_FUNCTIONS']['FILE']),
2080 'require_once' => Array(Array(1), $arResult['SECURING_FUNCTIONS']['FILE']),
2081 'set_include_path' => Array(Array(1), $arResult['SECURING_FUNCTIONS']['FILE']),
2082 ),
2083 'EXEC' => Array(
2084 'backticks' => Array(Array(1), Array()),
2085 'exec' => Array(Array(1), Array()),
2086 'passthru' => Array(Array(1), Array()),
2087 'pcntl_exec' => Array(Array(1), $arResult['SECURING_FUNCTIONS']['SYSTEM']),
2088 'popen' => Array(Array(1), $arResult['SECURING_FUNCTIONS']['SYSTEM']),
2089 'proc_open' => Array(Array(1), $arResult['SECURING_FUNCTIONS']['SYSTEM']),
2090 'shell_exec' => Array(Array(1), Array()),
2091 'system' => Array(Array(1), Array()),
2092 'mail' => Array(Array(5), Array()),
2093 'bxmail' => Array(Array(5), Array())
2094 ),
2095 'DATABASE' => Array(
2096 'query' => Array(Array(1), $arResult['SECURING_FUNCTIONS']['SQL']),
2097 'mysql_query' => Array(Array(1), $arResult['SECURING_FUNCTIONS']['SQL'])
2098 ),
2099 'OTHER' => Array(
2100 'dl' => Array(Array(1), Array()),
2101 'ereg' => Array(Array(2), Array()),
2102 'eregi' => Array(Array(2), Array()),
2103 'sleep' => Array(Array(1), Array()),
2104 // It's too difficult to validate, maybe in future versions
2105 'unserialize' => Array(Array(1), Array()),
2106 //'extract' => Array(Array(1), Array()),
2107 //'mb_parse_str' => Array(Array(1), Array()),
2108 //'parse_str' => Array(Array(1), Array()),
2109 //'define' => Array(Array(1), Array())
2110 ),
2111 'POP' => Array(
2112 'unserialize' => Array(Array(1), Array()),
2113 'is_a' => Array(Array(1), Array())
2114 )
2115 );
2116 $arResult['USER_INPUTS'] = Array(
2117 '$_GET',
2118 '$_POST',
2119 '$_COOKIE',
2120 '$_REQUEST',
2121 //'$_FILES', // Maybe later
2122 //'$_SERVER', // Maybe later
2123 '$_ENV',
2124 '$HTTP_GET_VARS',
2125 '$HTTP_POST_VARS',
2126 '$HTTP_COOKIE_VARS',
2127 '$HTTP_REQUEST_VARS',
2128 '$HTTP_POST_FILES',
2129 '$HTTP_SERVER_VARS',
2130 '$HTTP_ENV_VARS',
2131 '$HTTP_RAW_POST_DATA',
2132 '$argc',
2133 '$argv'
2134 );
2135
2136 $arResult['INIT_FUNCTIONS'] = Array(
2137 'initbvar',
2138 'initbvarfromarr'
2139 );
2140
2141 $arResult['COLORS']=array(
2142 T_DOLLAR_OPEN_CURLY_BRACES => '#007700',
2143 T_CURLY_OPEN => '#007700',
2144 T_OPEN_TAG => '#007700',
2145 T_CLOSE_TAG => '#007700',
2146 T_AND_EQUAL => '#007700',
2147 T_CONCAT_EQUAL => '#007700',
2148 T_DIV_EQUAL => '#007700',
2149 T_MINUS_EQUAL => '#007700',
2150 T_MOD_EQUAL => '#007700',
2151 T_MUL_EQUAL => '#007700',
2152 T_OR_EQUAL => '#007700',
2153 T_PLUS_EQUAL => '#007700',
2154 T_SL_EQUAL => '#007700',
2155 T_SR_EQUAL => '#007700',
2156 T_XOR_EQUAL => '#007700',
2157 T_IS_EQUAL => '#007700',
2158 T_IS_GREATER_OR_EQUAL => '#007700',
2159 T_IS_IDENTICAL => '#007700',
2160 T_IS_NOT_EQUAL => '#007700',
2161 T_IS_NOT_IDENTICAL => '#007700',
2162 T_INC => '#007700',
2163 T_DEC => '#007700',
2164 T_OBJECT_OPERATOR => '#007700',
2165 T_IF => '#007700',
2166 T_SWITCH => '#007700',
2167 T_WHILE => '#007700',
2168 T_DO => '#007700',
2169 T_EXIT => '#007700',
2170 T_TRY => '#007700',
2171 T_CATCH => '#007700',
2172 T_ISSET => '#007700',
2173 T_FOR => '#007700',
2174 T_FOREACH => '#007700',
2175 T_RETURN => '#007700',
2176 T_DOUBLE_ARROW => '#007700',
2177 T_AS => '#007700',
2178 T_CASE => '#007700',
2179 T_DEFAULT => '#007700',
2180 T_BREAK => '#007700',
2181 T_CONTINUE => '#007700',
2182 T_GOTO => '#007700',
2183 T_GLOBAL => '#007700',
2184 T_LOGICAL_AND => '#007700',
2185 T_LOGICAL_OR => '#007700',
2186 T_EMPTY => '#007700',
2187 T_UNSET => '#007700',
2188 T_ELSE => '#007700',
2189 T_ELSEIF => '#007700',
2190 T_LIST => '#007700',
2191 T_ARRAY => '#007700',
2192 T_ECHO => '#007700',
2193 T_START_HEREDOC => '#007700',
2194 T_END_HEREDOC => '#007700',
2195 T_FUNCTION => '#007700',
2196 T_PUBLIC => '#007700',
2197 T_PRIVATE => '#007700',
2198 T_PROTECTED => '#007700',
2199 T_STATIC => '#007700',
2200 T_CLASS => '#007700',
2201 T_NEW => '#007700',
2202 T_PRINT => '#007700',
2203 T_INCLUDE => '#007700',
2204 T_INCLUDE_ONCE => '#007700',
2205 T_REQUIRE => '#007700',
2206 T_REQUIRE_ONCE => '#007700',
2207 T_USE => '#007700',
2208 T_VAR => '#007700',
2209 T_BOOL_CAST => '#007700',
2210 T_DOUBLE_CAST => '#007700',
2211 T_INT_CAST => '#007700',
2212 T_UNSET_CAST => '#007700',
2213 T_BOOLEAN_OR => '#007700',
2214 T_BOOLEAN_AND => '#007700',
2215 T_FILE => '#007700',
2216 T_LINE => '#007700',
2217 T_DIR => '#007700',
2218 T_FUNC_C => '#007700',
2219 T_CLASS_C => '#007700',
2220 T_METHOD_C => '#007700',
2221 T_NS_C => '#007700',
2222 T_CONST => '#0000BB',
2223 T_VARIABLE => '#0000BB',
2224 T_STRING_VARNAME => '#0000BB',
2225 T_STRING => '#0000BB',
2226 T_EVAL => '#0000BB',
2227 T_LNUMBER => '#0000BB',
2228 T_ENCAPSED_AND_WHITESPACE => '#DD0000;',
2229 T_CONSTANT_ENCAPSED_STRING => '#DD0000;',
2230 T_INLINE_HTML => '#000000;',
2231 T_COMMENT => '#FF8000;',
2232 T_DOC_COMMENT => '#FF8000;'
2233 );
2234 ini_set('auto_detect_line_endings', 1);
2235 ini_set('short_open_tag', 1);
2236
2237 return $arResult;
2238 }
2239
2240 static private function getCurTemplate($path, $mp_mode=false)
2241 {
2242 if(!$mp_mode)
2243 {
2244 $dbSiteRes=CSite::GetTemplateList(CSite::GetSiteByFullPath($path, true));
2245 if(($arSiteRes = $dbSiteRes->Fetch()) !== false)
2246 return $arSiteRes['TEMPLATE'];
2247 }
2248 return '.default';
2249 }
2250 static public function checkVulnerabilities($arParams)
2251 {
2252 if(extension_loaded('tokenizer') === true)
2253 {
2254 if(empty(\Bitrix\Main\Application::getInstance()->getSession()['BX_CHECKLIST'][$arParams['TEST_ID']]))
2255 \Bitrix\Main\Application::getInstance()->getSession()['BX_CHECKLIST'][$arParams['TEST_ID']] = Array();
2256 $NS = &\Bitrix\Main\Application::getInstance()->getSession()['BX_CHECKLIST'][$arParams['TEST_ID']];
2257
2258 $arScanParams = self::defineScanParams();
2259 $phpMaxExecutionTime = ini_get("max_execution_time");
2260 $arScanParams['time_out'] = $phpMaxExecutionTime > 0 ? $phpMaxExecutionTime - 2: 30;
2261 $arScanParams['time_start'] = time();
2262 $arScanParams['MP_mode'] = false;
2263
2264 if($arParams['STEP'] === 0)
2265 {
2266 $NS = Array();
2267
2268 $NS['CUR_FILE_ID'] = 0;
2269 $NS['FILE_LIST'] = array();
2270 $NS['DIR_LIST'] = array();
2271 self::getFiles(
2272 $arScanParams['path'],
2273 $arScanParams['PREG_FOR_SKIP_SCAN'],
2274 $arScanParams['FILE_TYPES'],
2275 $arScanParams['path'],
2276 $NS['FILE_LIST'],
2277 $NS['DIR_LIST']
2278 );
2279 $NS['VULN_COUNT'] = 0;
2280 $NS['STUCK_FILE'] = -1;
2281 $NS['MESSAGE'] = Array();
2282 }
2283
2284 $time_end = $arScanParams['time_start'] + $arScanParams['time_out'];
2285 while ($NS['DIR_LIST'] && $time_end > time())
2286 {
2287 $dir = array_shift($NS['DIR_LIST']);
2288 self::getFiles(
2289 $dir,
2290 $arScanParams['PREG_FOR_SKIP_SCAN'],
2291 $arScanParams['FILE_TYPES'],
2292 $arScanParams['path'],
2293 $NS['FILE_LIST'],
2294 $NS['DIR_LIST']
2295 );
2296 }
2297
2298 if ($NS['DIR_LIST'])
2299 {
2300 return Array(
2301 'IN_PROGRESS' => 'Y',
2302 'PERCENT' => 0,
2303 );
2304 }
2305
2306 $result=true;
2307 do
2308 {
2309 if(is_file($file = $NS['FILE_LIST'][$NS['CUR_FILE_ID']]))
2310 {
2311 if(isset($output))
2312 unset($output);
2313 if(isset($scan))
2314 unset($scan);
2315
2316 $scan = new CVulnScanner($file, $arScanParams, self::getCurTemplate($file, $arScanParams['MP_mode']));
2317 $result = $scan->process();
2318 if($result !== false)
2319 {
2320 if($scan->vuln_count > 0)
2321 {
2322 $NS['MESSAGE'][$NS['CUR_FILE_ID']]['VULN_COUNT'] = $scan->vuln_count;
2323 $NS['MESSAGE'][$NS['CUR_FILE_ID']]['OUTPUT'] = $scan->getOutput();
2324 }
2325 $NS['CUR_FILE_ID']++;
2326 }
2327 else
2328 {
2329 if($NS['STUCK_FILE'] === $NS['CUR_FILE_ID'])
2330 {
2331 $NS['CUR_FILE_ID']++;
2332 $NS['STUCK_FILE'] = -1;
2333 }
2334 else
2335 $NS['STUCK_FILE'] = $NS['CUR_FILE_ID'];
2336 }
2337 }
2338 else
2339 {
2340 $NS['CUR_FILE_ID']++;
2341 }
2342
2343 } while ($NS['CUR_FILE_ID'] < count($NS['FILE_LIST']) && $result !== false);
2344
2345 if(!($NS['CUR_FILE_ID'] < count($NS['FILE_LIST'])))
2346 {
2347 $arDetailReport = '';
2348 $vulnCount=0;
2349 foreach ($NS['MESSAGE'] as $file_output)
2350 if (!empty($file_output))
2351 if (!str_contains($arDetailReport, $file_output['OUTPUT']))
2352 {
2353 $arDetailReport .= $file_output['OUTPUT'];
2354 $vulnCount += $file_output['VULN_COUNT'];
2355 }
2356
2357 unset(\Bitrix\Main\Application::getInstance()->getSession()['BX_CHECKLIST'][$arParams['TEST_ID']]);
2358
2359 $arResult = Array(
2360 'MESSAGE' => Array(
2361 'PREVIEW' => GetMessage('VULNSCAN_FIULECHECKED').count($NS['FILE_LIST']).GetMessage('VULNSCAN_VULNCOUNTS').$vulnCount,
2362 'PROBLEM_COUNT' => $vulnCount,
2363 'DETAIL' => $arDetailReport
2364 ),
2365 'STATUS' => ($vulnCount > 0 ? false : true)
2366 );
2367 }
2368 else
2369 {
2370 $percent = round(($NS['CUR_FILE_ID']) / (count($NS['FILE_LIST']) * 0.01), 0);
2371 $arResult = Array(
2372 'IN_PROGRESS' => 'Y',
2373 'PERCENT' => number_format($percent, 2),
2374 );
2375 }
2376 }
2377 else
2378 {
2379 $arResult = Array(
2380 'MESSAGE' => Array(
2381 'PREVIEW' => GetMessage('VULNSCAN_TOKENIZER_NOT_INSTALLED'),
2382 ),
2383 'STATUS' => false
2384 );
2385 }
2386 return $arResult;
2387 }
2388
2389}
2390
2391
2392?>
return[Dependency::CONTAINER=> Container::class, Dependency::IBLOCK_INFO=> IblockInfo::class, Dependency::PRODUCT_CONVERTER=> ProductConverter::class, Dependency::REPOSITORY_FACADE=> Repository::class, Dependency::PRODUCT_FACTORY=> ProductFactory::class, Dependency::PRODUCT_REPOSITORY=> ProductRepository::class, ProductFactory::PRODUCT=> Product::class, Dependency::SECTION_FACTORY=> SectionFactory::class, Dependency::SECTION_REPOSITORY=> SectionRepository::class, SectionFactory::SECTION=> Section::class, SectionFactory::SECTION_COLLECTION=> SectionCollection::class, Dependency::SKU_FACTORY=> SkuFactory::class, Dependency::SKU_REPOSITORY=> SkuRepository::class, SkuFactory::SIMPLE_SKU=> SimpleSku::class, SkuFactory::SKU=> Sku::class, SkuFactory::SKU_COLLECTION=> SkuCollection::class, Dependency::PROPERTY_FACTORY=> PropertyFactory::class, Dependency::PROPERTY_REPOSITORY=> PropertyRepository::class, PropertyFactory::PROPERTY=> Property::class, PropertyFactory::PROPERTY_COLLECTION=> PropertyCollection::class, Dependency::PROPERTY_VALUE_FACTORY=> PropertyValueFactory::class, PropertyValueFactory::PROPERTY_VALUE=> PropertyValue::class, PropertyValueFactory::PROPERTY_VALUE_COLLECTION=> PropertyValueCollection::class, Dependency::PROPERTY_FEATURE_FACTORY=> PropertyFeatureFactory::class, Dependency::PROPERTY_FEATURE_REPOSITORY=> PropertyFeatureRepository::class, PropertyFeatureFactory::PROPERTY_FEATURE=> PropertyFeature::class, PropertyFeatureFactory::PROPERTY_FEATURE_COLLECTION=> PropertyFeatureCollection::class, Dependency::PRICE_FACTORY=> PriceFactory::class, Dependency::PRICE_REPOSITORY=> PriceRepository::class, PriceFactory::SIMPLE_PRICE=> SimplePrice::class, PriceFactory::QUANTITY_DEPENDENT_PRICE=> QuantityDependentPrice::class, PriceFactory::PRICE_COLLECTION=> PriceCollection::class, Dependency::IMAGE_FACTORY=> ImageFactory::class, Dependency::IMAGE_REPOSITORY=> ImageRepository::class, ImageFactory::DETAIL_IMAGE=> DetailImage::class, ImageFactory::PREVIEW_IMAGE=> PreviewImage::class, ImageFactory::MORE_PHOTO_IMAGE=> MorePhotoImage::class, ImageFactory::IMAGE_COLLECTION=> ImageCollection::class, Dependency::MEASURE_RATIO_FACTORY=> MeasureRatioFactory::class, Dependency::MEASURE_RATIO_REPOSITORY=> MeasureRatioRepository::class, MeasureRatioFactory::SIMPLE_MEASURE_RATIO=> SimpleMeasureRatio::class, MeasureRatioFactory::MEASURE_RATIO_COLLECTION=> MeasureRatioCollection::class, Dependency::BARCODE_FACTORY=> BarcodeFactory::class, Dependency::BARCODE_REPOSITORY=> BarcodeRepository::class, BarcodeFactory::BARCODE=> Barcode::class, BarcodeFactory::BARCODE_COLLECTION=> BarcodeCollection::class, Dependency::STORE_PRODUCT_FACTORY=> StoreProductFactory::class, Dependency::STORE_PRODUCT_REPOSITORY=> StoreProductRepository::class, StoreProductFactory::STORE_PRODUCT=> StoreProduct::class, StoreProductFactory::STORE_PRODUCT_COLLECTION=> StoreProductCollection::class, 'sku.tree'=> SkuTree::class, 'integration.seo.facebook.facade'=> FacebookFacade::class, 'integration.seo.facebook.product.processor'=> FacebookProductProcessor::class, 'integration.seo.facebook.product.repository'=> FacebookProductRepository::class,]
Определения .container.php:139
$arParams
Определения access_dialog.php:21
$path
Определения access_edit.php:21
$count
Определения admin_tab.php:4
$type
Определения options.php:106
$arResult
Определения generate_coupon.php:16
static getInstance()
Определения application.php:98
static checkVulnerabilities($arParams)
Определения vuln_scanner.php:2250
Определения vuln_scanner.php:7
$tainted_vars
Определения vuln_scanner.php:14
$start
Определения vuln_scanner.php:9
$line
Определения vuln_scanner.php:8
$comment
Определения vuln_scanner.php:11
__construct($id, $line, $start, $end, $tokens, $comment, $dependencies, $tainted_vars)
Определения vuln_scanner.php:17
$tokens
Определения vuln_scanner.php:12
$dependencies
Определения vuln_scanner.php:13
$end
Определения vuln_scanner.php:10
$id
Определения vuln_scanner.php:15
Определения vuln_scanner.php:31
$declares
Определения vuln_scanner.php:32
$requestInitialization
Определения vuln_scanner.php:36
__construct($name)
Определения vuln_scanner.php:38
newDeclare($id, $line, $start, $end, $tokens, $comment, $dependencies, $tainted_vars)
Определения vuln_scanner.php:47
$name
Определения vuln_scanner.php:35
$have_user_input
Определения vuln_scanner.php:33
$secure
Определения vuln_scanner.php:34
Определения vuln_scanner.php:54
$filename
Определения vuln_scanner.php:61
$additional_text
Определения vuln_scanner.php:63
$tainted_vars
Определения vuln_scanner.php:58
$line
Определения vuln_scanner.php:60
$comment
Определения vuln_scanner.php:55
$tokens
Определения vuln_scanner.php:56
$dependencies
Определения vuln_scanner.php:57
__construct($filename, $line, $name, $tokens, $dependencies, $tainted_vars, $comment)
Определения vuln_scanner.php:65
$traverse
Определения vuln_scanner.php:62
$name
Определения vuln_scanner.php:59
Определения vuln_scanner.php:81
$arResult
Определения vuln_scanner.php:84
__construct($file_name, $arParams, $template='.default', $component_template='')
Определения vuln_scanner.php:111
process()
Определения vuln_scanner.php:388
$vuln_count
Определения vuln_scanner.php:83
tokenize($code, $component_template='')
Определения vuln_scanner.php:850
getOutput()
Определения vuln_scanner.php:1700
while( $arBasket=$dbBasket->Fetch())
Определения commerceml.php:73
$f
Определения component_props.php:52
if(!is_array($prop["VALUES"])) $tmp
Определения component_props.php:203
& nbsp
Определения epilog_main_admin.php:38
$filename
Определения file_edit.php:47
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
background color
Определения file_new.php:745
$res
Определения filter_act.php:7
$handle
Определения include.php:55
$result
Определения get_property_values.php:14
$start
Определения get_search.php:9
$output
Определения options.php:436
$_SERVER["DOCUMENT_ROOT"]
Определения cron_frame.php:9
if(!is_null($config))($config as $configItem)(! $configItem->isVisible()) $code
Определения options.php:195
if(!defined('NOT_CHECK_PERMISSIONS')) $NS
Определения backup.php:24
htmlspecialcharsbx($string, $flags=ENT_COMPAT, $doubleEncode=true)
Определения tools.php:2701
IncludeModuleLangFile($filepath, $lang=false, $bReturnArray=false)
Определения tools.php:3778
GetMessage($name, $aReplace=null)
Определения tools.php:3397
$name
Определения menu_edit.php:35
$value
Определения Param.php:39
$var
Определения payment.php:63
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
$dir
Определения quickway.php:303
if(empty($signedUserToken)) $key
Определения quickway.php:257
$text
Определения template_pdf.php:79
$i
Определения factura.php:643
font style
Определения invoice.php:442
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
Определения waybill.php:936
for( $i=0, $max=count( $arShownFieldsParams);$i< $max;$i++)
Определения csv.php:28
$comment
Определения template.php:15
$val
Определения options.php:1793
$k
Определения template_pdf.php:567
$max
Определения template_copy.php:262
if(!defined("T_BAD_CHARACTER")) define("T_BAD_CHARACTER"
Определения vuln_scanner.php:4
switch( $_REQUEST[ 'bxsender'])().Authorize(<? break
Определения wrapper_popup.php:7