/** * @return void * @covers \pFlow\Analyzer<extended> * @group pflow * @group unittest */ public function testSetSourceDirectory() { $analyzer = new Analyzer(); $analyzer->setSources(array(__DIR__ . '/data'), true); $resultFiles = $analyzer->getFiles(); $expectedFiles = array(__DIR__ . "/data/MainClass.php", __DIR__ . "/data/module1/Module1.php"); $this->assertSubset($expectedFiles, $resultFiles, "recursive file search of data directory failed"); }
/** * */ public function testGetClassesFromFile() { $analyzer = new Analyzer(); $result = $analyzer->getClassReflections(__DIR__ . '/resources/tokenizerClasses.php'); $this->assertCount(2, $result); $this->assertSame('Foo\\class2', $result['Foo\\class2']->getName()); $this->assertSame('Foo\\class3', $result['Foo\\class3']->getName()); }
public function loadTmplVar($varname, $path) { $analyzer = new Analyzer(); $analyzer->analyzeFile($path); $elementList = $analyzer->getElementList(); $this->_subtmplList = array_merge($this->_subtmplList, $analyzer->getSubTmplList()); $this->_varList[$varname] = $elementList; $this->_varListType[$varname] = 'ELEMENTLIST'; }
private function doNextCase() { $case = $this->testCases[static::$nextCase++]; $num = static::$nextCase; $label = Analyzer::analyze($case['txt'], true)->label; $expected = $case['expected']; echo "\n{$num}. got {$label}; expected {$expected}\n"; $this->assertTrue($label == $case['expected']); }
public function testsimpleAnalyze() { //TODO benchmark for ($i = 0; $i < 1000; $i++) { Analyzer::analyze($this->getPseudoRandomWord(), true); $it = ++static::$iterations; echo "iterated {$it} times...\n"; } }
private static function analyzePayload($payload) { $analyzedPosts = array(); $decodedPayload = json_decode($payload); $posts = $decodedPayload->posts; foreach ($posts as $post) { $feeling = Analyzer::analyze($post->text); $analyzed = (object) array('id' => $post->id, 'feeling' => $feeling, 'tags' => $post->tags); $analyzedPosts[] = $analyzed; } return $analyzedPosts; }
public function store(Request $request) { $user = \Helper::getUser(); $customer = \Helper::getCustomer(); if ($customer->is_registered) { return '请勿重复注册'; } $validator = \Validator::make($request->all(), ['phone' => 'required|digits:11|unique:customers,phone,' . $customer->id, 'code' => 'required|digits:6']); if ($validator->fails()) { return redirect()->back()->withErrors($validator)->withInput(); } if ($request->input('code') != $customer->auth_code || $request->input('code') == '000000') { return redirect()->back()->with('error_message', '验证码不匹配!')->withInput(); } if (Carbon::now()->diffInMinutes($customer->auth_code_expire) > 0) { return redirect()->back()->with('error_message', '验证码过期!')->withInput(); } $beans_total_update = 0; if ($customer->beans_total > 0) { $beans_total_update = $customer->beans_total; } $customer->update(['phone' => $request->input('phone'), 'is_registered' => true, 'beans_total' => $beans_total_update, 'nickname' => $user['nickname'], 'head_image_url' => $user['headimgurl'], 'qr_code' => \Wechat::getForeverQrCodeUrl($customer->id)]); if ($ci = CustomerInformation::where('phone', '=', $request->input('phone'))->first()) { $ci->customer_id = $customer->id; $ci->save(); } // $ret = $customer->register(); if ($customer->referrer_id) { // \BeanRecharger::invite($customer->getReferrer()); \Analyzer::updateBasicStatistics($customer->referrer_id, AnalyzerConstant::CUSTOMER_FRIEND); } \EnterpriseAnalyzer::updateBasic(AnalyzerConstant::ENTERPRISE_REGISTER); event(new Register($customer)); if (\Session::has('register_next_url')) { return redirect(\Session::get('register_next_url')); } return redirect('register/success'); }
public function createFieldDefinitions($tableName, $key) { $value = $this->newSchemes[$tableName][$key]; $sql = ''; $sql .= "`" . $value['column'] . "` " . $value['type_name'] . " " . ($value['nullable'] ? 'NULL' : 'NOT NULL'); if (isset($value['default'])) { $sql .= ' DEFAULT '; if ($value['default'] === 'NULL') { $sql .= 'NULL'; } else { $sql .= "'" . $this->newDatabase->escape($value['default']) . "'"; } } if (count(array_filter($this->newSchemes[$tableName], function ($col) { return isset($col['key']) && $col['key'] === true; })) === 1 && isset($value['key']) && $value['key'] === true) { $sql .= ' ' . 'PRIMARY KEY'; } if (isset($value['extra'])) { $sql .= ' ' . $value['extra']; } return $sql; }
public function articleIndex(Request $request) { $customer = \Helper::getCustomerOrNull(); if (!$customer) { if (!$customer->articleIndexNeedFeedBack()) { \Log::info('hongbao---111'); } else { \Log::info('hongbao---222'); } } else { \Log::info('hongbao---333'); } if (!$customer || !$customer->articleIndexNeedFeedBack()) { \Log::info('hongbao---不存在'); \Analyzer::updateBasicStatistics($customer->id, AnalyzerConstant::CUSTOMER_ARTICLE); return redirect("http://mp.weixin.qq.com/mp/homepage?__biz=MzI4NTAxMzc3Mw==&hid=1&sn=740141c97f60c8630a87a3f0c344a504#wechat_redirect"); } else { \Log::info('hongbao---存在'); $count = $customer->readArticleIndex(); \BeanRecharger::executeEducation($customer); \Analyzer::updateBasicStatistics($customer->id, AnalyzerConstant::CUSTOMER_ARTICLE); return view('education.hongbao')->with(['redirect_url' => "http://mp.weixin.qq.com/mp/homepage?__biz=MzI4NTAxMzc3Mw==&hid=1&sn=740141c97f60c8630a87a3f0c344a504#wechat_redirect", 'count' => $count]); } }
/** * */ protected function updateStatistics() { foreach ($this->commodities()->get(['id'])->pluck('id') as $commodity_id) { \Analyzer::updateCommodityStatistics($this->customer_id, $commodity_id); \Analyzer::updateBasicStatistics($this->customer_id, AnalyzerConstant::CUSTOMER_COMMODITY); \EnterpriseAnalyzer::updateCommodityStatistics($commodity_id); } \Analyzer::updateBasicStatistics($this->customer_id, AnalyzerConstant::CUSTOMER_ORDER); \Analyzer::updateBasicStatistics($this->customer_id, AnalyzerConstant::CUSTOMER_MONEY_COST, $this->cash_payment); \EnterpriseAnalyzer::updateBasic(AnalyzerConstant::ENTERPRISE_ORDER); \EnterpriseAnalyzer::updateBasic(AnalyzerConstant::ENTERPRISE_COMMODITY, $this->commodities()->count()); \EnterpriseAnalyzer::updateBasic(AnalyzerConstant::ENTERPRISE_INCOME, $this->cash_payment); \EnterpriseAnalyzer::updateBasic(AnalyzerConstant::ENTERPRISE_BEAN, $this->beans_payment); }
// Register shortcut functions function e($string) { echo htmlspecialchars($string, ENT_QUOTES, 'UTF-8'); } function d() { return call_user_func_array('Debugger::debug', func_get_args()); } // Start the firewall Firewall::start(); // Start the session Session::start(); // Analyze the PHP code if (Debugger::$enabled) { Analyzer::execute(); } // Load the action into body ob_start(); if (Router::getTemplateAction()) { require Router::getTemplateAction(); } if (ob_get_contents()) { ob_end_flush(); trigger_error('MindaPHP template action"' . Router::getTemplateAction() . '" should not send output. Error raised ', E_USER_WARNING); } else { ob_end_clean(); } ob_start(); if (Router::getAction()) { extract(Router::getParameters());
/** * @param Analyzer $analyzer * The case being analyzed -- to which we want to add an activity. * @param \SimpleXMLElement $actXML the <ActivityType> tag which describes the new activity */ public function createActivity(Analyzer $analyzer, \SimpleXMLElement $actXML) { $params = array('activity_type_id' => (string) $actXML->name, 'status_id' => 'Scheduled', 'activity_date_time' => \CRM_Utils_Time::getTime('YmdHis'), 'case_id' => $analyzer->getCaseId()); $r = civicrm_api3('Activity', 'create', $params); $analyzer->flush(); }
<?php /** * Created by PhpStorm. * User: bamdad * Date: 2/3/2016 * Time: 9:02 PM */ include_once './autoload.php'; $analyzer = new Analyzer("http://www.gutenberg.org/files/31205/31205-h/31205-h.htm"); //enter your stopwords as input to this function so they won't be counted in frequency $analyzer->getSummary(['the', 'of']); return 0;
/** * Запускаем отрисовку виджета * * @return void */ public function run() { // Авторизован ли пользователь if (Yii::app()->user->isAuthenticated() === false) { return; } if (($user = Yii::app()->user->getProfile()) === null) { return; } // Загрузка таблицы для блока $table = Table::model()->with(array('markup'))->findByPK((int) $this->model_id); if ($table === null) { return; } // Генерируем уникальный код таблицы $tableCode = $this->block_id !== null ? $this->block_id . '-' : ''; $tableCode .= $table->id . '-' . mt_rand(100000, 999999); // Устанавливаем источники данных $personForm = new PersonForm(); $eventForm = new EventForm(); $beforeDescription = ''; $afterDescription = ''; $useAltTable = false; // Если Персона не установлена if ($this->person === null) { // Если источник данных - данные пользователя, // то берем все данные из профиля пользователя if ($table->source_destiny_table == Table::SOURCE_USER) { $this->person = new Person(); $this->person->setAttributes(array('name' => $user->profile->name, 'gender' => $user->profile->gender, 'date' => $user->profile->birth_date, 'time' => $user->profile->birth_time, 'city_id' => $user->profile->city_id)); } elseif ($table->source_destiny_table == Table::SOURCE_ADMIN) { $this->person = $table->person; } } // Если Событие не установлено if ($this->event === null) { // Если источник данных - данные от администратора, // то берем данные из БД if ($table->source_event_table == Table::SOURCE_ADMIN) { $this->event = $table->event; } } // Проверка данных if ($this->person !== null) { $validateResult = $this->person->validate(); $validateResult = $validateResult && ($this->event !== null ? $this->event->validate() : true); } // Если данные корректны if ($validateResult) { // Создаем калькулятор $calculator = new Calculator($this->person, $this->event); // Определяем активный столп if ($table->active_luck_pillar > 0) { $calculator->numCurrentLuckColumn = (int) $table->active_luck_pillar; } // Запуск расчета $calculator->run(); // Если задана разметка, запускаем анализаторы if (!empty($table->markup)) { // Анализатор $analyzer = new Analyzer($calculator); // Запуск анализа $analyzer->run(); $markupAnalyzer = new MarkupAnalyzer($table, $analyzer); $markupAnalyzer->run(); //var_dump($markupAnalyzer->getFoundedMarkupItems()); //exit(); // Найденные элементы разметки $foundedMarkupItems = $markupAnalyzer->getFoundedMarkupItems(); $useIndividualDescription = false; // Если не найден ни один элемент разметки if (empty($foundedMarkupItems)) { // Если используется альтернативная таблица if ($table->source_destiny_table == Table::SOURCE_USER && $table->use_alt_table) { // Используем альтернативную таблицу // Создаем калькулятор $calculator = new Calculator($table->altTable, $this->event); // Определяем активный столп if ($table->active_luck_pillar > 0) { $calculator->numCurrentLuckColumn = (int) $table->active_luck_pillar; } // Запуск расчета $calculator->run(); // Анализатор $analyzer = new Analyzer($calculator); $analyzer->run(); $markupAnalyzer = new MarkupAnalyzer($table, $analyzer); $markupAnalyzer->run(); // Альтернативное описание if ($table->description_place == Table::DESCRIPTION_PLACE_BEFORE) { $beforeDescription = $table->alt_description; } elseif ($table->description_place == Table::DESCRIPTION_PLACE_AFTER) { $afterDescription = $table->alt_description; } $useAltTable = true; } else { // В противном случае выводим основное описание if ($table->description_place == Table::DESCRIPTION_PLACE_BEFORE) { $beforeDescription = $table->description; } elseif ($table->description_place == Table::DESCRIPTION_PLACE_AFTER) { $afterDescription = $table->description; } } } else { $useIndividualDescription = true; } if ($useIndividualDescription) { // Формируем описания до таблиц и после для каждой найденной разметки foreach ($foundedMarkupItems as $markupItem) { if ($markupItem->description_place == TableMarkup::DESCRIPTION_PLACE_BEFORE) { // Общее описание $beforeDescription .= $markupItem->description; // Описание для женщины $beforeDescription .= $this->person->gender == Person::GENDER_FEMALE && $markupItem->description_f != '' ? $markupItem->description_f : ''; // Описание для мужчины $beforeDescription .= $this->person->gender == Person::GENDER_MALE && $markupItem->description_m != '' ? $markupItem->description_m : ''; } elseif ($markupItem->description_place == TableMarkup::DESCRIPTION_PLACE_AFTER) { // Общее описание $afterDescription .= $markupItem->description; // Описание для женщины $afterDescription .= $this->person->gender == Person::GENDER_FEMALE && $markupItem->description_f != '' ? $markupItem->description_f : ''; // Описание для мужчины $afterDescription .= $this->person->gender == Person::GENDER_MALE && $markupItem->description_m != '' ? $markupItem->description_m : ''; } } } } } else { // Формируем список ошибок $errors = array(); if ($this->person !== null) { foreach ($this->person->getErrors() as $key => $error) { $errors['Person'][$key] = $error; } } if ($this->event !== null) { foreach ($this->event->getErrors() as $key => $error) { $errors['Event'][$key] = $error; } } } //var_dump($beforeDescription); // Вывод в шаблон if (Yii::app()->request->isAjaxRequest) { // Если аякс-запрос, то перерисовываем только чарт $this->controller->renderPartial('//bazi/widgets/TableWidget/_chart', array('model' => $table, 'tableCode' => $tableCode, 'calculator' => $calculator, 'beforeDescription' => $beforeDescription, 'afterDescription' => $afterDescription, 'useAltTable' => $useAltTable, 'markupCells' => isset($markupAnalyzer) ? $markupAnalyzer->getMarkupCells() : array(), 'markupRelations' => isset($markupAnalyzer) ? $markupAnalyzer->getMarkupRelations() : array())); } else { $this->render($this->view, array('model' => $table, 'tableCode' => $tableCode, 'calculator' => $calculator, 'beforeDescription' => $beforeDescription, 'afterDescription' => $afterDescription, 'useAltTable' => $useAltTable, 'personForm' => $personForm, 'eventForm' => $eventForm, 'errors' => $errors, 'markupCells' => isset($markupAnalyzer) ? $markupAnalyzer->getMarkupCells() : array(), 'markupRelations' => isset($markupAnalyzer) ? $markupAnalyzer->getMarkupRelations() : array())); } }
public function pass_6() { $tokens = token_get_all($this->source[$this->last_pass]); $token_count = count($tokens); $tp = 0; $tokens_to_patch = array('T_FUNCTION'); $last_class = ''; while ($tp < $token_count) { $token_name = $this->token_name($tokens[$tp]); if ($token_name == 'T_NAMESPACE') { $current_namespace = $this->token_content($tokens[$this->get_next_non_comment($tokens, $tp + 1)]); } if ($token_name == 'T_CLASS') { $last_class = $this->token_content($tokens[$this->get_next_non_comment($tokens, $tp + 1)]); if (isset($current_namespace)) { $last_class = $current_namespace . "\\" . $last_class; } } if (in_array($token_name, $tokens_to_patch)) { if ($blockstart = $this->search_token($tokens, $tp, '{', array(';'))) { $function_name_tp = $this->get_next_non_comment($tokens, $tp + 1); if (!is_array($tokens[$function_name_tp])) { $function_name_tp = $this->get_next_non_comment($tokens, $function_name_tp + 1); } $function_name = $tokens[$function_name_tp][1]; if (!Analyzer::shouldpatch($function_name, $last_class)) { $tp++; continue; } //Analyzer::$instancenumberfor[$function_name] = 0; $this->add_tokens_to_be_inserted_after($blockstart + 1, "", 0); $blockend = $this->get_pair($tokens, $blockstart); $children = $this->get_children_from($tokens, $blockstart, $blockend, 0, $temp, true); //Analyzer::$possiblebranches[$function_name] = $children->getPaths(); } } $tp++; } $this->source[$this->current_pass] = $this->change_stuff(); }
public function updateBean(Request $request) { $customer = \Helper::getCustomer(); if (!$customer) { return response()->json(['result' => '-1']); } /*if>*/ if (!$customer->is_registered) { return response()->json(['result' => '-1']); } /*if>*/ $article = Article::where('id', $request->input('id'))->first(); \Analyzer::updateArticleStatistics($customer->id, $article->type_id); \Analyzer::updateBasicStatistics($customer->id, AnalyzerConstant::CUSTOMER_ARTICLE); \EnterpriseAnalyzer::updateArticleStatistics($article->type_id); \EnterpriseAnalyzer::updateBasic(AnalyzerConstant::ENTERPRISE_ARTICLE); if (\DailyAnalyzer::getDailyItemCount($customer->id, AnalyzerConstant::CUSTOMER_DAILY_ARTICLE)) { \DailyAnalyzer::updateDailyItemCount($customer->id, AnalyzerConstant::CUSTOMER_DAILY_ARTICLE); return response()->json(['result' => '-1']); } \DailyAnalyzer::updateDailyItemCount($customer->id, AnalyzerConstant::CUSTOMER_DAILY_ARTICLE); \BeanRecharger::executeEducation($customer); return response()->json(['result' => '1']); }
public function executeSave($id) { $data = $this->execute($id); $data['data'] = json_encode($data['data']); $this->create(); $this->save($data, false); App::import('Analyzer'); $analyzer = new Analyzer(); $analyzer->save(array('id' => $id, 'execution_id' => $this->id, 'execution_ts' => $data['completition_ts'])); echo "{$id} "; }
public static function analyzer() { $signatureResolver = new SignatureResolver(); $analyzer = new Analyzer(); $analyzer->addVisitor(new AstProcessor\ReferenceKiller()); $analyzer->addVisitor(new AstProcessor\AssignOpResolver()); $analyzer->addVisitor(new AstProcessor\LoopResolver()); $analyzer->addVisitor(new AstProcessor\ElseIfResolver()); $analyzer->addVisitor(new AstProcessor\SignatureResolver($signatureResolver)); $analyzer->addVisitor(new AstProcessor\RecursionResolver()); $analyzer->addProcessor(new GraphProcessor\SSACompiler()); $resolver = new GraphProcessor\Optimizer(); $resolver->addRule(new OptimizerRule\Assign()); $resolver->addRule(new OptimizerRule\BinaryOp()); $resolver->addRule(new OptimizerRule\BooleanNot()); $resolver->addRule(new OptimizerRule\BitwiseNot()); $resolver->addRule(new OptimizerRule\ConstBinaryOp()); $resolver->addRule(new OptimizerRule\DeadAssignmentRemover()); $resolver->addRule(new OptimizerRule\FunctionCall()); $resolver->addRule(new OptimizerRule\Phi()); $resolver->addRule(new OptimizerRule\UnreachableCode()); $analyzer->addProcessor($resolver); $analyzer->addProcessor(new GraphProcessor\PhiResolver()); $analyzer->addProcessor(new GraphProcessor\FreeResolver()); return $analyzer; }
function parse() { // scan all tokens for ($i = 0, $tokencount = count($this->tokens); $i < $tokencount; $i++, $this->tif++) { if (is_array($this->tokens[$i])) { $token_name = $this->tokens[$i][0]; $token_value = $this->tokens[$i][1]; $line_nr = $this->tokens[$i][2]; // add preloader info for big files if ($line_nr % PRELOAD_SHOW_LINE == 0) { echo $GLOBALS['fit'] . '|' . $GLOBALS['file_amount'] . '|' . $this->file_pointer . ' (line ' . $line_nr . ')|' . $GLOBALS['timeleft'] . '|' . "\n"; @ob_flush(); flush(); } # debug #echo "file:".$file_name.",line:".$line_nr.",token:".token_name($token_name).","; #echo "value:".htmlentities($token_value).","; #echo "in_function:".$in_function.",in_class:".$in_class."<br>"; /************************* T_VARIABLE *************************/ if ($token_name === T_VARIABLE) { // $var() if ($this->tokens[$i + 1][0] === '(') { $this->variable_scan($i, 0, 'eval', 'Userinput is used as dynamic function name. Arbitrary functions may be called.'); } else { if (($this->tokens[$i - 1] === '$' || $this->tokens[$i - 1] === '{' && $this->tokens[$i - 2] === '$') && ($this->tokens[$i + 1] === '=' || in_array($this->tokens[$i + 1][0], Tokens::$T_ASSIGNMENT))) { $this->variable_scan($i, $this->tokens[$i - 1] === '{' ? 2 : 1, 'extract', 'Userinput is used to build the variable name. Arbitrary variables may be overwritten/initialized which may lead to further vulnerabilities.'); } else { if ($this->tokens[$i - 1][0] === T_AS || $this->tokens[$i - 1][0] === T_DOUBLE_ARROW && $this->tokens[$i - 2][0] === T_VARIABLE && $this->tokens[$i - 3][0] === T_AS) { $c = 3; while ($this->tokens[$i - $c][0] !== T_FOREACH) { $c++; if ($i - $c < 0 || $this->tokens[$i - $c] === ';') { addError('Could not find FOREACH token before AS token', array_slice($this->tokens, $i - 5, 10), $this->tokens[$i - 1][2], $this->file_pointer); break; } } $this->variable_add($token_value, array_slice($this->tokens, $i - $c, $c + Analyzer::getBraceEnd($this->tokens, $i)), '', 0, 0, $line_nr, $i, isset($this->tokens[$i][3]) ? $this->tokens[$i][3] : array()); } else { if ($this->tokens[$i - 2][0] === T_FOR && ($this->tokens[$i + 1] === '=' || in_array($this->tokens[$i + 1][0], Tokens::$T_ASSIGNMENT))) { $c = 1; $newbraceopen = 1; $firstsemi = 0; // do not use getBraceEnd() here, because we dont want to stop at ';' in for(;;) while ($newbraceopen !== 0) { // watch function calls in function call if ($this->tokens[$i + $c] === '(') { $newbraceopen++; } else { if ($this->tokens[$i + $c] === ')') { $newbraceopen--; } else { if ($this->tokens[$i + $c] === ';' && $firstsemi < 1) { $firstsemi = $c; } } } $c++; if (!isset($this->tokens[$i + $c])) { addError('Could not find closing parenthesis of for-statement.', array_slice($this->tokens, $i - 2, 10), $this->tokens[$i - 2][2], $this->file_pointer); break; } } // overwrite value of first var because it is looped // this is an assumption, other vars could be declared for($var1=1;$var2=2;...) $this->tokens[$i + 2][0] = T_ENCAPSED_AND_WHITESPACE; $this->tokens[$i + 2][1] = '*'; $this->variable_add($token_value, array_slice($this->tokens, $i - 2, $c + 2), '', 1, 2 + $firstsemi, $line_nr, $i, isset($this->tokens[$i][3]) ? $this->tokens[$i][3] : array()); } else { if ($this->tokens[$i + 1] === '=' || in_array($this->tokens[$i + 1][0], Tokens::$T_ASSIGNMENT)) { $vardeclare = array(); // $var = array(1,2,3,4); if ($this->tokens[$i + 2][0] === T_ARRAY && $this->tokens[$i + 3] === '(' && $this->tokens[$i + 4] !== ')') { $d = 4; $keyindex = 0; $newbraceopen = 1; $keytokens = array(); $valuetokens = array(); while (!($newbraceopen === 0 || $this->tokens[$i + $d] === ';') && $keyindex < MAX_ARRAY_ELEMENTS) { // count parameters if ($newbraceopen === 1 && ($this->tokens[$i + $d] === ',' || $this->tokens[$i + $d] === ')')) { $newindexvar = $this->tokens[$i]; $newindexvar[3][] = empty($keytokens) ? $keyindex : $keytokens; $this->variable_add($token_value, array_merge(array($newindexvar, $this->tokens[$i + 1]), $valuetokens), ' array() ', in_array($this->tokens[$i + 1][0], Tokens::$T_ASSIGNMENT) ? 0 : 1, 0, $line_nr, $i, isset($this->tokens[$i][3]) ? $this->tokens[$i][3] : array(), empty($keytokens) ? $keyindex : $keytokens); $keyindex++; $keytokens = array(); $valuetokens = array(); } else { if ($this->tokens[$i + $d] === '(') { $newbraceopen++; } else { if ($this->tokens[$i + $d] === ')') { $newbraceopen--; } else { if ($this->tokens[$i + $d][0] === T_DOUBLE_ARROW) { $keytokens = $valuetokens; $valuetokens = array(); } else { $valuetokens[] = $this->tokens[$i + $d]; } } } } $d++; if (!isset($this->tokens[$i + $d])) { addError('Could not find closing parenthesis of array()-declaration.', array_slice($this->tokens, $i, 10), $this->tokens[$i + 2][2], $this->file_pointer); break; } } $vardeclare['end'] = Analyzer::getBraceEnd($this->tokens, $i) + 1; // $var = anything; } else { $this->variable_add($token_value, array_slice($this->tokens, $i, $vardeclare['end'] = Analyzer::getBraceEnd($this->tokens, $i) + 1), '', in_array($this->tokens[$i + 1][0], Tokens::$T_ASSIGNMENT) ? 0 : 1, 0, $line_nr, $i, isset($this->tokens[$i][3]) ? $this->tokens[$i][3] : array()); } // save var and var declare scope for data leak scan $vardeclare['start'] = $i; $vardeclare['name'] = $token_value; $vardeclare['linenr'] = $line_nr; $vardeclare['end'] += $i - 1; } } } } } // $class->var //else if ($token_name === T_STRING && $tokens[$i-1][0] === T_OBJECT_OPERATOR && $tokens[$i-2][0] === T_VARIABLE) // add user input variables to global finding list if (in_array($token_value, Sources::$V_USERINPUT)) { if (isset($this->tokens[$i][3])) { if (!is_array($this->tokens[$i][3][0])) { $GLOBALS['user_input'][$token_value . '[' . $this->tokens[$i][3][0] . ']'][$this->file_pointer][] = $line_nr; } else { $GLOBALS['user_input'][$token_value . '[' . Analyzer::get_tokens_value($this->file_pointer, $this->tokens[$i][3][0], $this->in_function ? $this->var_declares_local : $this->var_declares_global, $this->var_declares_global, $i) . ']'][$this->file_pointer][] = $line_nr; } } else { $GLOBALS['user_input'][$token_value][$this->file_pointer][] = $line_nr; } // count found userinput in function for graphs if ($this->in_function) { $GLOBALS['user_functions_offset'][$this->function_obj->name][5]++; } else { $GLOBALS['user_functions_offset']['__main__'][5]++; } } } else { if (in_array($token_name, Tokens::$T_FUNCTIONS) || in_array($token_name, Tokens::$T_XSS) && ($_POST['vector'] == 'client' || $_POST['vector'] == 'xss' || $_POST['vector'] == 'all')) { $class = ''; /************************* T_STRING *************************/ if ($token_name === T_STRING && $this->tokens[$i + 1] === '(') { // define("FOO", $_GET['asd']); if ($token_value === 'define') { $c = 1; while ($this->tokens[$i + $c] !== ',') { $c++; if ($this->tokens[$i + $c] === ';' || !isset($this->tokens[$i + $c])) { addError('Second parameter of define() is missing.', array_slice($this->tokens, $i, $c), $this->tokens[$i][2], $this->file_pointer); break; } } $this->variable_add(str_replace(array('"', "'"), '', $this->tokens[$i + 2][1]), array_slice($this->tokens, $i, Analyzer::getBraceEnd($this->tokens, $i) + 1), ' define() ', $c, 0, $line_nr, $i); } else { if ($token_value === 'ini_set') { $setting = str_replace(array("'", '"'), '', $this->tokens[$i + 2][1]); // ini_set('include_path', 'foo/bar') if ($setting === 'include_path') { $path = Analyzer::get_tokens_value($this->file_pointer, array_slice($this->tokens, $i + 4, Analyzer::getBraceEnd($this->tokens, $i + 4) + 1), $this->in_function ? $this->var_declares_local : $this->var_declares_global, $this->var_declares_global, $i); $this->include_paths = array_unique(array_merge($this->include_paths, Analyzer::get_ini_paths($path))); } } else { if ($token_value === 'set_include_path') { $path = Analyzer::get_tokens_value($this->file_pointer, array_slice($this->tokens, $i + 1, Analyzer::getBraceEnd($this->tokens, $i + 1) + 1), $this->in_function ? $this->var_declares_local : $this->var_declares_global, $this->var_declares_global, $i); $this->include_paths = array_unique(array_merge($this->include_paths, Analyzer::get_ini_paths($path))); } else { if ($token_value === 'set_error_handler') { $token_value = str_replace(array('"', "'"), '', $this->tokens[$i + 2][1]); } else { if ($token_value === 'compact' && $this->tokens[$i - 2][0] === T_VARIABLE) { $f = 2; while ($this->tokens[$i + $f] !== ')') { // for all array keys save new variable declarations if ($this->tokens[$i + $f][0] === T_CONSTANT_ENCAPSED_STRING) { $this->variable_add($this->tokens[$i - 2][1], array(array(T_VARIABLE, $this->tokens[$i - 2][1], $line_nr, array(str_replace(array('"', "'"), '', $this->tokens[$i + $f][1]))), '=', array(T_VARIABLE, '$' . str_replace(array('"', "'"), '', $this->tokens[$i + $f][1]), $line_nr), ';'), ' compact() ', 2, 0, $line_nr, $i, $tokens[$i - 2][3], str_replace(array('"', "'"), '', $this->tokens[$i + $f][1])); } $f++; if ($this->tokens[$i + $f] === ';' || !isset($this->tokens[$i + $f])) { addError('Closing parenthesis of compact() is missing.', array_slice($this->tokens, $i, $f), $this->tokens[$i][2], $this->file_pointer); break; } } } else { if ($token_value === 'preg_match' || $token_value === 'preg_match_all') { $c = 2; $parameter = 1; $newbraceopen = 1; while ($newbraceopen !== 0) { if (is_array($this->tokens[$i + $c]) && $this->tokens[$i + $c][0] === T_VARIABLE && $parameter == 3) { // add variable declaration to beginning of varlist // fake assignment parameter so it will not get traced $this->variable_add($this->tokens[$i + $c][1], array_slice($this->tokens, $i, Analyzer::getBraceEnd($this->tokens, $i + 2) + 3), ' preg_match() ', 0, $c - 1, $this->tokens[$i + $c][2], $i, isset($this->tokens[$i + $c][3]) ? $this->tokens[$i + $c][3] : array()); } else { if ($newbraceopen === 1 && $this->tokens[$i + $c] === ',') { $parameter++; } else { if ($this->tokens[$i + $c] === '(') { $newbraceopen++; } else { if ($this->tokens[$i + $c] === ')') { $newbraceopen--; } else { if ($this->tokens[$i + $c] === ';' || !isset($this->tokens[$i + $c])) { addError('Closing parenthesis of ' . $token_value . '() is missing.', array_slice($this->tokens, $i, $c), $this->tokens[$i][2], $this->file_pointer); break; } } } } } $c++; } } else { if ($token_value === 'import_request_variables') { // add register_globals implementation $this->variable_add('register_globals', array_slice($this->tokens, $i, Analyzer::getBraceEnd($this->tokens, $i + 1) + 1), 'register_globals implementation', 0, 0, $line_nr, $i, isset($this->tokens[$i][3]) ? $this->tokens[$i][3] : array()); } else { if ($token_value === 'parse_str') { $c = 2; $parameter = 1; $newbraceopen = 1; while ($newbraceopen !== 0) { if (is_array($this->tokens[$i + $c]) && $this->tokens[$i + $c][0] === T_VARIABLE && $parameter == 2) { // add variable declaration to beginning of varlist // fake assignment parameter so it will not get traced $this->variable_add($this->tokens[$i + $c][1], array_slice($this->tokens, $i, Analyzer::getBraceEnd($this->tokens, $i + 2) + 3), ' parse_str() ', 0, $c - 1, $this->tokens[$i + $c][2], $i, isset($this->tokens[$i + $c][3]) ? $this->tokens[$i + $c][3] : array()); } else { if ($newbraceopen === 1 && $this->tokens[$i + $c] === ',') { $parameter++; } else { if ($this->tokens[$i + $c] === '(') { $newbraceopen++; } else { if ($this->tokens[$i + $c] === ')') { $newbraceopen--; } else { if ($this->tokens[$i + $c] === ';' || !isset($this->tokens[$i + $c])) { addError('Closing parenthesis of ' . $token_value . '() is missing.', array_slice($this->tokens, $i, $c), $this->tokens[$i][2], $this->file_pointer); break; } } } } } $c++; } } } } } } } } } //add interesting function calls to info gathering if (isset($this->info_functions[$token_value])) { $GLOBALS['info'][] = $this->info_functions[$token_value]; } else { if ($this->tokens[$i - 1][0] !== T_NEW && isset($this->vuln_classes[$token_value])) { $this->class_vars[$this->tokens[$i - 2][1]] = $token_value; } else { // $classvar->bla() if ($this->tokens[$i - 1][0] === T_OBJECT_OPERATOR) { $classvar = $this->tokens[$i - 2][1]; if ($classvar[0] !== '$') { $classvar = '$' . $classvar; } $class = $classvar === '$this' || $classvar === '$self' ? $this->class_name : $this->class_vars[$classvar]; } else { if ($this->tokens[$i - 1][0] === T_DOUBLE_COLON) { $class = $this->tokens[$i - 2][1]; } } // save function call for graph if (isset($GLOBALS['user_functions_offset'][($class ? $class . '::' : '') . $token_value])) { $GLOBALS['user_functions_offset'][($class ? $class . '::' : '') . $token_value][3][] = array($this->file_pointer, $line_nr); if ($this->in_function) { $GLOBALS['user_functions_offset'][$this->function_obj->name][4][] = $token_value; } else { $GLOBALS['user_functions_offset']['__main__'][4][] = $token_value; } } // check if token is function call that affects variable scope (global) if (isset($this->globals_from_function[$token_value])) { // put all previously saved global var assignments to global scope foreach ($this->globals_from_function[$token_value] as $var_name => $new_vars) { foreach ($new_vars as $new_var) { $new_var->comment = $new_var->comment . " by {$token_value}()"; if (!isset($this->var_declares_global[$var_name])) { $this->var_declares_global[$var_name] = array($new_var); } else { array_unshift($this->var_declares_global[$var_name], $new_var); } } } } } } } else { if (in_array($token_name, Tokens::$T_INCLUDES) && !$this->in_function) { $GLOBALS['count_inc']++; // include('xxx') if ($this->tokens[$i + 1] === '(' && $this->tokens[$i + 2][0] === T_CONSTANT_ENCAPSED_STRING && $this->tokens[$i + 3] === ')' || is_array($this->tokens[$i + 1]) && $this->tokens[$i + 1][0] === T_CONSTANT_ENCAPSED_STRING && $this->tokens[$i + 2] === ';') { // include('file') if ($this->tokens[$i + 1] === '(') { $inc_file = substr($this->tokens[$i + 2][1], 1, -1); $skip = 5; } else { $inc_file = substr($this->tokens[$i + 1][1], 1, -1); $skip = 3; } } else { $inc_file = Analyzer::get_tokens_value($this->file_pointer, array_slice($this->tokens, $i + 1, $c = Analyzer::getBraceEnd($this->tokens, $i + 1) + 1), $this->in_function ? $this->var_declares_local : $this->var_declares_global, $this->var_declares_global, $i); // in case the get_var_value added several php files, take the first $several = explode('.php', $inc_file); if (count($several) > 1) { $try_file = $several[0] . '.php'; } $skip = $c + 1; // important to save $c+1 here } $try_file = $inc_file; // try absolute include path foreach ($this->include_paths as $include_path) { if (is_file("{$include_path}/{$try_file}")) { $try_file = "{$include_path}/{$try_file}"; break; } } // if dirname(__FILE__) appeared it was an absolute path if (!is_file($try_file)) { // check relativ path $try_file = dirname($this->file_name) . '/' . $inc_file; if (!is_file($try_file)) { $other_try_file = dirname($this->file_pointer) . '/' . $inc_file; // if file can not be found check include_path if set if (!is_file($other_try_file)) { if (isset($this->include_paths[0])) { foreach ($this->include_paths as $include_path) { if (is_file(dirname($this->file_name) . '/' . $include_path . '/' . $inc_file)) { $try_file = dirname($this->file_name) . '/' . $include_path . '/' . $inc_file; break; } else { if (is_file(dirname($this->file_pointer) . '/' . $include_path . '/' . $inc_file)) { $try_file = dirname($this->file_pointer) . '/' . $include_path . '/' . $inc_file; break; } } } } // if still not a valid file, look a directory above if (!is_file($try_file)) { $try_file = str_replace('\\', '/', $try_file); $pos = strlen($try_file); // replace each found / with /../, start from the end of file name for ($c = 1; $c < substr_count($try_file, '/'); $c++) { $pos = strripos(substr($try_file, 1, $pos), '/'); if (is_file(substr_replace($try_file, '/../', $pos + 1, 1))) { $try_file = substr_replace($try_file, '/../', $pos + 1, 1); break; } } if (!is_file($try_file)) { $try_file = str_replace('\\', '/', $other_try_file); $pos = strlen($try_file); // replace each found / with /../, start from the end of file name for ($c = 1; $c < substr_count($try_file, '/'); $c++) { $pos = strripos(substr($try_file, 1, $pos), '/'); if (is_file(substr_replace($try_file, '/../', $pos + 1, 1))) { $try_file = substr_replace($try_file, '/../', $pos + 1, 1); break; } } // if still not a valid file, guess it if (!is_file($try_file)) { $searchfile = basename($try_file); if (!strstr($searchfile, '$_USERINPUT')) { foreach ($GLOBALS['files'] as $cfile) { if (basename($cfile) == $searchfile) { $try_file = $cfile; break; } } } } } } } else { $try_file = $other_try_file; } } } $try_file_unreal = $try_file; $try_file = realpath($try_file); // file is valid if (!empty($try_file_unreal) && !empty($try_file) && ($inc_lines = @file($try_file_unreal))) { // file name has not been included if (!in_array($try_file, $this->inc_map)) { // Tokens $tokenizer = new Tokenizer($try_file); $inc_tokens = $tokenizer->tokenize(implode('', $inc_lines)); unset($tokenizer); // if(include('file')) { - include tokens after { and not into the condition :S if ($this->in_condition) { $this->tokens = array_merge(array_slice($this->tokens, 0, $this->in_condition + 1), $inc_tokens, array(array(T_INCLUDE_END, 0, 1)), array_slice($this->tokens, $this->in_condition + 1)); } else { // insert included tokens in current tokenlist and mark end $this->tokens = array_merge(array_slice($this->tokens, 0, $i + $skip), $inc_tokens, array(array(T_INCLUDE_END, 0, 1)), array_slice($this->tokens, $i + $skip)); } $tokencount = count($this->tokens); // set lines pointer to included lines, save last pointer // (the following tokens will be the included ones) $this->lines_stack[] = $inc_lines; $this->lines_pointer = end($this->lines_stack); // tokennr in file $this->tif_stack[] = $this->tif; $this->tif = -$skip; // set the current file pointer $this->file_pointer = $try_file; if (!isset($GLOBALS['file_sinks_count'][$this->file_pointer])) { $GLOBALS['file_sinks_count'][$this->file_pointer] = 0; } echo $GLOBALS['fit'] . '|' . $GLOBALS['file_amount'] . '|' . $this->file_pointer . '|' . $GLOBALS['timeleft'] . '|' . "\n"; @ob_flush(); flush(); $this->comment = basename($inc_file); $this->inc_file_stack[] = $try_file; // build include map for file list $this->inc_map[] = $try_file; // all basic includes } } else { $GLOBALS['count_inc_fail']++; // add information about include error in debug mode if ($GLOBALS['verbosity'] == 5) { // add include command to output $found_value = highlightline(array_slice($this->tokens, $i, $skip), $this->comment, $line_nr, $token_value); $new_find = new InfoTreeNode($found_value); $new_find->lines[] = $line_nr; $new_find->filename = $this->file_pointer; $new_find->title = "Include error: tried to include: " . $try_file_unreal; if (isset($GLOBALS['output'][$this->file_name]['inc'])) { $GLOBALS['output'][$this->file_name]['inc']->treenodes[] = $new_find; } else { $new_block = new VulnBlock($this->tif . '_' . $this->tokens[$i][2] . '_' . basename($this->file_pointer), 'Debug'); $new_block->treenodes[] = $new_find; $new_block->vuln = true; $GLOBALS['output'][$this->file_name]['inc'] = $new_block; } } } } } /************************* TAINT ANALYSIS *************************/ if (isset($this->scan_functions[$token_value]) && $GLOBALS['verbosity'] != 5 && (empty($class) || ($this->in_function && is_array($function_obj->parameters) && in_array($classvar, $function_obj->parameters) || @in_array($token_value, $this->vuln_classes[$class])))) { if (!$this->already_scanned($i)) { // build new find $new_find = new VulnTreeNode(); $new_find->name = $token_value; $new_find->lines[] = $line_nr; // add dependencies (already here, because checked during var trace foreach ($this->dependencies as $deplinenr => $dependency) { if (!empty($dependency)) { $new_find->dependencies[$deplinenr] = $dependency; } } // count sinks $GLOBALS['file_sinks_count'][$this->file_pointer]++; if ($this->in_function) { $GLOBALS['user_functions_offset'][$this->function_obj->name][6]++; } else { $GLOBALS['user_functions_offset']['__main__'][6]++; } $parameter = 1; $var_counter = 0; $vulnparams = array(0); $has_vuln_parameters = false; $parameter_has_userinput = false; $parameter_func_depend = false; $secured_by_start = false; // function calls without quotes (require $inc;) --> no brace count $parentheses_open = $this->tokens[$i + 1] === '(' ? 1 : -2; // -2: detection of braces doesnt matter $parentheses_save = -1; $in_securing = false; $ignore_securing = false; $c = $this->tokens[$i + 1] === '(' ? 2 : 1; // important $tainted_vars = array(); $reconstructstr = ''; $addtitle = ''; $this->securedby = array(); // get all variables in parameter list between (...) // not only until ';' because: system(get($a),$b,strstr($c)); while ($parentheses_open !== 0 && $this->tokens[$i + $c] !== ';') { $this_one_is_secure = false; if (is_array($this->tokens[$i + $c])) { // scan variables and constants if ($this->tokens[$i + $c][0] === T_VARIABLE && $this->tokens[$i + $c + 1][0] !== T_OBJECT_OPERATOR || $this->tokens[$i + $c][0] === T_STRING && $this->tokens[$i + $c + 1] !== '(') { $var_counter++; // scan only potential vulnerable parameters of function call if (in_array($parameter, $this->scan_functions[$token_value][0]) || isset($this->scan_functions[$token_value][0][0]) && $this->scan_functions[$token_value][0][0] === 0) { $has_vuln_parameters = true; if (is_array($this->tokens[$i + $c - 1]) && in_array($this->tokens[$i + $c - 1][0], Tokens::$T_CASTS) || is_array($this->tokens[$i + $c + 1]) && in_array($this->tokens[$i + $c + 1][0], Tokens::$T_ARITHMETIC) || $in_securing) { $secured_by_start = true; $this_one_is_secure = true; } if ($in_securing && !$ignore_securing) { $this->securedby[] = $securing_function; } // trace back parameters and look for userinput, trace constants globally $userinput = $this->scan_parameter($new_find, $new_find, $this->tokens[$i + $c], $this->tokens[$i + $c][3], $i + $c, $this->in_function && $this->tokens[$i + $c][1][0] === '$' ? $this->var_declares_local : $this->var_declares_global, $this->var_declares_global, false, $this->scan_functions[$token_value][1], false, $ignore_securing, $this_one_is_secure || $in_securing); $reconstructstr .= Analyzer::get_var_value($this->file_pointer, $this->tokens[$i + $c], $this->in_function && $this->tokens[$i + $c][1][0] === '$' ? $this->var_declares_local : $this->var_declares_global, $this->var_declares_global, $i + $c, $this->source_functions); if ($userinput) { $vulnparams[] = $parameter; if ($userinput == 1) { $parameter_has_userinput = true; } else { if ($userinput == 2) { $parameter_func_depend = true; } } $tainted_vars[] = $var_counter; } } // mark userinput for quote analysis if (in_array($this->tokens[$i + $c][1], Sources::$V_USERINPUT)) { $reconstructstr .= '$_USERINPUT'; } } else { if ($this->tokens[$i + $c][0] === T_STRING && in_array($this->tokens[$i + $c][1], $this->source_functions) && (in_array($parameter, $this->scan_functions[$token_value][0]) || isset($this->scan_functions[$token_value][0][0]) && $this->scan_functions[$token_value][0][0] === 0)) { $has_vuln_parameters = true; $parameter_has_userinput = true; $new_find->marker = 1; $reconstructstr .= '$_USERINPUT'; $new_find->title = 'Userinput returned by function <i>' . $this->tokens[$i + $c][1] . '</i> reaches sensitive sink'; $this->addtriggerfunction($new_find); } else { if ($this->tokens[$i + $c][0] === T_STRING && isset($this->tokens[$i + $c][1]) && in_array($this->tokens[$i + $c][1], $GLOBALS['F_INSECURING_STRING']) && $parentheses_save == -1) { $parentheses_save = $parentheses_open; $ignore_securing = true; } else { if (!$ignore_securing && ($this->tokens[$i + $c][0] === T_STRING && (is_array($this->scan_functions[$token_value][1]) && in_array($this->tokens[$i + $c][1], $this->scan_functions[$token_value][1]) || in_array($this->tokens[$i + $c][1], $GLOBALS['F_SECURING_STRING']))) || in_array($this->tokens[$i + $c][0], Tokens::$T_CASTS) && $this->tokens[$i + $c + 1] === '(') { $securing_function = $this->tokens[$i + $c][1]; $parentheses_save = $parentheses_open; $in_securing = true; $secured_by_start = true; } else { if ($this->tokens[$i + $c][0] === T_CONSTANT_ENCAPSED_STRING) { $reconstructstr .= substr($this->tokens[$i + $c][1], 1, -1); } else { if ($this->tokens[$i + $c][0] === T_ENCAPSED_AND_WHITESPACE) { $reconstructstr .= $this->tokens[$i + $c][1]; } } } } } } } else { if ($parentheses_open === 1 && $this->tokens[$i + $c] === ',') { $parameter++; } else { if ($this->tokens[$i + $c] === '(') { $parentheses_open++; } else { if ($this->tokens[$i + $c] === ')') { $parentheses_open--; if ($parentheses_open === $parentheses_save) { $parentheses_save = -1; $in_securing = false; $securing_function = ''; $ignore_securing = false; } } else { if (!isset($this->tokens[$i + $c])) { addError('Closing parenthesis of ' . $token_value . '() is missing.', array_slice($this->tokens, $i, 10), $this->tokens[$i][2], $this->file_pointer); break; } } } } } $c++; } // quote analysis for securing functions F_QUOTE_ANALYSIS // they only protect when return value is embedded into quotes if ($this->quote_analysis_needed() && substr_count($reconstructstr, '$_USERINPUT') > 0) { // idea: explode on $_USERINPUT and count quotes in SQL query before // if not even, then the $_USERINPUT is in an open quote $parts = explode('$_USERINPUT', $reconstructstr); foreach ($this->securedby as $var => $securefunction) { if (in_array($securefunction, $GLOBALS['F_QUOTE_ANALYSIS'])) { // extract the string before the userinput $checkstring = ''; $d = 1; foreach ($parts as $part) { $checkstring .= $part; if ($d >= $var) { break; } $d++; } // even amount of quotes (or none) in string // --> no quotes around userinput // --> securing function is useless if (substr_count($checkstring, "'") % 2 === 0 && substr_count($checkstring, '"') % 2 === 0) { $has_vuln_parameters = true; $parameter_has_userinput = true; $new_find->title .= "Userinput reaches sensitive sink due to insecure usage of {$securefunction}() without quotes"; } } } } // add find to output if function call has variable parameters (With userinput) if ($has_vuln_parameters && ($parameter_has_userinput || $parameter_func_depend) || $GLOBALS['verbosity'] == 4 || isset($this->scan_functions[$token_value][3])) { $vulnstart = $i; $vulnadd = 1; // prepend $var assignment if (isset($vardeclare)) { $vulnstart = $vardeclare['start']; $vulnadd = $vardeclare['end'] - $vardeclare['start'] - $c + 1; //3; } else { if (isset($GLOBALS['F_XSS'][$this->tokens[$i - 1][1]])) { $vulnstart = $i - 1; $vulnadd = 2; } else { if ($this->tokens[$i - 1][0] === T_DOUBLE_COLON || $this->tokens[$i - 1][0] === T_OBJECT_OPERATOR) { $vulnstart = $i - 2; $vulnadd = 2; } } } if (isset($GLOBALS['user_functions'][$this->file_name][$token_value])) { $found_line = '<A NAME="' . $token_value . '_call" class="jumplink"></A>'; $found_line .= highlightline(array_slice($this->tokens, $vulnstart, $c + $vulnadd), $this->comment, $line_nr, false, $token_value); } else { $found_line = highlightline(array_slice($this->tokens, $vulnstart, $c + $vulnadd), $this->comment, $line_nr, $token_value, false, $tainted_vars); } $new_find->value = $found_line; $new_find->filename = $this->file_pointer; if ($secured_by_start) { $new_find->marker = 2; } // only show vuln user defined functions // if call with userinput has been found if (isset($GLOBALS['user_functions'][$this->file_name][$token_value])) { $GLOBALS['user_functions'][$this->file_name][$token_value]['called'] = true; } if ($this->in_function) { $this->ignore_securing_function = true; // mark function in class as vuln if ($this->in_class) { $this->vuln_classes[$this->class_name][] = $this->function_obj->name; } } // putenv with userinput --> getenv is treated as userinput if ($token_value === 'putenv') { $this->source_functions[] = 'getenv'; $GLOBALS['source_functions'][] = 'getenv'; $new_find->title = 'User can set PHP enviroment variables. Adding getenv() to tainting functions'; } else { if ($token_value === 'apache_setenv') { $this->source_functions[] = 'apache_getenv'; $GLOBALS['source_functions'][] = 'apache_getenv'; $new_find->title = 'User can set Apache enviroment variables. Adding apache_getenv() to tainting functions'; } else { if ($token_value === 'extract' || $token_value === 'parse_str' || $token_value === 'mb_parse_str') { // add register_globals implementation $this->variable_add('register_globals', array_slice($this->tokens, $vulnstart, $c + $vulnadd), 'register_globals implementation', 0, 0, $line_nr, $i, isset($this->tokens[$i][3]) ? $this->tokens[$i][3] : array()); } } } // add to output if (isset($GLOBALS['user_functions'][$this->file_name][$token_value])) { if (!empty($GLOBALS['output'][$this->file_name])) { foreach ($GLOBALS['output'][$this->file_name] as $block) { $calleesadded = array(); foreach ($block->treenodes as $tree) { if ($tree->funcdepend === $token_value && (array_intersect($tree->funcparamdepend, $vulnparams) || isset($this->scan_functions[$token_value][3]))) { // if funcdependend already found and added, just add foundcallee=true and continue // dont add tree again, it is already added to the vulnblock if (in_array($tree->funcdepend, $calleesadded)) { $tree->foundcallee = true; continue; } if (isset($this->scan_functions[$token_value][3])) { $new_find->title = 'Call triggers vulnerability in function <i>' . $token_value . '()</i>'; } else { if (empty($new_find->title)) { $new_find->title = 'Userinput is passed through function parameters.'; } } $block->treenodes[] = $new_find; if (!$block->vuln && ($parameter_has_userinput || isset($this->scan_functions[$token_value][3]) || $GLOBALS['verbosity'] == 4)) { $block->vuln = true; increaseVulnCounter($block->sink); } $tree->foundcallee = true; $calleesadded[] = $token_value; } } } // else: dont use the result } } else { if (empty($new_find->title)) { $new_find->title = 'Userinput reaches sensitive sink. For more information, press the help icon on the left side.'; } $block = new VulnBlock($this->tif . '_' . $this->tokens[$i][2] . '_' . basename($this->file_pointer), getVulnNodeTitle($token_value), $token_value); $block->treenodes[] = $new_find; if ($parameter_has_userinput || $GLOBALS['verbosity'] == 4) { $block->vuln = true; increaseVulnCounter($token_value); } // if sink in var declare, offer a data leak scan - save infos for that if (isset($vardeclare)) { $block->dataleakvar = array($vardeclare['linenr'], $vardeclare['name']); } $GLOBALS['output'][$this->file_name][] = $block; } } // if classvar depends on function parameter, add this parameter to list if (isset($this->classvar) && $this->in_function && in_array($this->classvar, $this->function_obj->parameters)) { $param = array_search($this->classvar, $this->function_obj->parameters); $GLOBALS['user_functions'][$this->file_name][$this->function_obj->name][0][$param] = $param + 1; } } } // taint analysis } else { if (in_array($token_name, Tokens::$T_LOOP_CONTROL)) { // ignore in requirements output: while, for, foreach // DO..WHILE was rewritten to WHILE in tokenizer $this->ignore_requirement = true; $c = 1; // get variables in loop condition while ($this->tokens[$i + $c] !== '{') { if ($this->tokens[$i + $c][0] === T_VARIABLE) { $this->tokens[$i + $c][3][] = '*'; } else { if (!isset($this->tokens[$i + $c])) { addError('Could not find opening brace after ' . $token_value . '-statement.', array_slice($this->tokens, $i, 10), $this->tokens[$i][2], $this->file_pointer); break; } } $c++; } } else { if (in_array($token_name, Tokens::$T_FLOW_CONTROL)) { $c = 1; while ($this->tokens[$i + $c] !== '{') { $c++; if (!isset($this->tokens[$i + $c])) { addError('Could not find opening brace after ' . $token_value . '-statement.', array_slice($this->tokens, $i, 10), $this->tokens[$i][2], $this->file_pointer); break; } } $this->in_condition = $i + $c; $this->dependencytokens = array_slice($this->tokens, $i, $c); } else { if ($token_name === T_FUNCTION) { if ($this->in_function) { #addError('New function declaration in function declaration of '.$this->function_obj->name.'() found. This is valid PHP syntax but not supported by RIPS now.', array_slice($this->tokens, $i, 10), $this->tokens[$i][2], $this->file_pointer); } else { $this->in_function++; // the next token is the "function name()" $i++; $function_name = isset($this->tokens[$i][1]) ? $this->tokens[$i][1] : $this->tokens[$i + 1][1]; $ref_name = ($this->in_class ? $this->class_name . '::' : '') . $function_name; // add POP gadgets to info if (isset($this->info_functions[$function_name])) { $GLOBALS['info'][] = $ref_name; // add gadget to output $found_line = highlightline(array_slice($this->tokens, $i - 1, 4), $this->comment, $line_nr, $function_name, false, $function_name); $new_find = new InfoTreeNode($found_line); $new_find->title = "POP gadget {$ref_name}"; $new_find->lines[] = $line_nr; $new_find->filename = $this->file_pointer; if (isset($GLOBALS['output'][$this->file_name]['gadgets'])) { $GLOBALS['output'][$this->file_name]['gadgets']->treenodes[] = $new_find; } else { $block = new VulnBlock($this->tif . '_' . $this->tokens[$i][2] . '_' . basename($this->file_pointer), 'POP gadgets'); $block->vuln = true; $block->treenodes[] = $new_find; $GLOBALS['output'][$this->file_name]['gadgets'] = $block; } } $c = 3; while ($this->tokens[$i + $c] !== '{' && $this->tokens[$i + $c] !== ';') { $c++; } // abstract functions ended if ($this->tokens[$i + $c] === ';') { $this->in_function--; } // write to user_functions offset list for referencing in output $GLOBALS['user_functions_offset'][$ref_name][0] = $this->file_pointer; $GLOBALS['user_functions_offset'][$ref_name][1] = $line_nr - 1; // save function as object $this->function_obj = new FunctionDeclare($this->dependencytokens = array_slice($this->tokens, $i - 1, $c + 1)); $this->function_obj->lines[] = $line_nr; $this->function_obj->name = $function_name; // save all function parameters $this->function_obj->parameters = array(); $e = 1; // until function test(...) { // OR // interface test { public function test(...); } while ($this->tokens[$i + $e] !== '{' && $this->tokens[$i + $e] !== ';') { if (is_array($this->tokens[$i + $e]) && $this->tokens[$i + $e][0] === T_VARIABLE) { $this->function_obj->parameters[] = $this->tokens[$i + $e][1]; } $e++; } // now skip the params from rest of scan, // or function test($a=false, $b=false) will be detected as var declaration $i += $e - 1; // -1, because '{' must be evaluated again } } else { if ($token_name === T_GLOBAL && $this->in_function) { $this->globals_from_function[$this->function_obj->name] = array(); // get all globaled variables $b = 1; while ($this->tokens[$i + $b] !== ';') { if ($this->tokens[$i + $b][0] === T_VARIABLE) { // mark variable as global scope affecting $this->put_in_global_scope[] = $this->tokens[$i + $b][1]; // add variable declaration to beginning of varlist $new_var = new VarDeclare(array(array(T_GLOBAL, 'global', $line_nr), array(T_VARIABLE, $this->tokens[$i + $b][1], $line_nr), ';'), $this->comment); $new_var->line = $line_nr; $new_var->id = $i; // overwrite old local vars $this->var_declares_local[$this->tokens[$i + $b][1]] = array($new_var); } $b++; } } else { if ($token_name === T_RETURN && $this->in_function == 1) { $GLOBALS['userfunction_taints'] = false; $GLOBALS['userfunction_secures'] = false; $c = 1; // get all variables in parameter list while ($this->tokens[$i + $c] !== ';') { if (is_array($this->tokens[$i + $c])) { if ($this->tokens[$i + $c][0] === T_VARIABLE) { // check if returned var is secured --> securing function $new_find = new VulnTreeNode(); $userinput = $this->scan_parameter($new_find, $new_find, $this->tokens[$i + $c], $this->tokens[$i + $c][3], $i + $c, $this->var_declares_local, $this->var_declares_global, false, $GLOBALS['F_SECURES_ALL'], TRUE); // add function to securing functions // if it returns no userinput/function param if ((!$userinput || $GLOBALS['userfunction_secures']) && !$this->ignore_securing_function) { $GLOBALS['F_SECURING_STRING'][] = $this->function_obj->name; } // add function to userinput functions if userinput // is fetched in the function and then returned (userinput == 1) if ($userinput == 1 || $GLOBALS['userfunction_taints']) { $this->source_functions[] = $this->function_obj->name; } } else { if (in_array($this->tokens[$i + $c][1], $GLOBALS['F_SECURES_ALL']) || in_array($this->tokens[$i + $c][0], Tokens::$T_CASTS)) { $GLOBALS['F_SECURING_STRING'][] = $this->function_obj->name; break; } } } $c++; } } else { if ($token_name === T_CLASS) { $i++; $this->class_name = $this->tokens[$i][1]; $this->vuln_classes[$this->class_name] = array(); $this->in_class = true; $GLOBALS['info'][] = '<font color="red">Code is object-oriented. This is not supported yet and can lead to false negatives.</font>'; } else { if ($token_name === T_NEW && $this->tokens[$i - 2][0] === T_VARIABLE) { $this->class_vars[$this->tokens[$i - 2][1]] = $this->tokens[$i + 1][1]; } else { if ($token_name === T_EXTENDS && $this->in_class) { $this->vuln_classes[$this->class_name] = $this->vuln_classes[$this->tokens[$i + 1][1]]; } else { if ($token_name === T_LIST) { $d = 2; while ($this->tokens[$i + $d] !== ')' && $this->tokens[$i + $d] !== ';') { $d++; if ($this->tokens[$i + $d] === ';' || !isset($this->tokens[$i + $d])) { addError('Closing parenthesis of list() is missing.', array_slice($this->tokens, $i, 10), $this->tokens[$i][2], $this->file_pointer); break; } } $tokenscanstart = 0; if ($this->tokens[$i + $d + 1] === '=' || in_array($this->tokens[$i + $d + 1][0], Tokens::$T_ASSIGNMENT)) { $tokenscanstart = $d + 1; } $c = 2; for ($c = 2; $c < $d; $c++) { if (is_array($this->tokens[$i + $c]) && $this->tokens[$i + $c][0] === T_VARIABLE) { $this->variable_add($this->tokens[$i + $c][1], array_slice($this->tokens, $i, Analyzer::getBraceEnd($this->tokens, $i) + 1), ' list() ', $tokenscanstart, 0, $this->tokens[$i + $c][2], $i, isset($this->tokens[$i + $c][3]) ? $this->tokens[$i + $c][3] : array()); } } $i = $i + $c + 2; } else { if ($token_name === T_INCLUDE_END) { array_pop($this->lines_stack); $this->lines_pointer = end($this->lines_stack); array_pop($this->inc_file_stack); $this->file_pointer = end($this->inc_file_stack); $this->comment = basename($this->file_pointer) == basename($this->file_name) ? '' : basename($this->file_pointer); $this->tif = array_pop($this->tif_stack); } } } } } } } } } } } } } else { /************************* BRACES *************************/ // keep track of { program blocks } // get current dependencies in program flow if ($this->tokens[$i] === '{' && ($this->tokens[$i - 1] === ')' || $this->tokens[$i - 1] === ':' || $this->tokens[$i - 1] === ';' || is_array($this->tokens[$i - 1]) && ($this->tokens[$i - 1][0] === T_DO || $this->tokens[$i - 1][0] === T_ELSE || $this->tokens[$i - 1][0] === T_STRING || $this->tokens[$i - 1][0] === T_TRY || $this->tokens[$i - 1][0] === T_CATCH))) { // save brace amount at start of function if ($this->in_function && $this->brace_save_func < 0) { $this->brace_save_func = $this->braces_open; } // save brace amount at start of class if ($this->in_class && $this->brace_save_class < 0) { $this->brace_save_class = $this->braces_open; } $this->in_condition = 0; if (empty($e)) { if (!$this->ignore_requirement) { if (!empty($this->dependencytokens) && $this->dependencytokens[0][0] === T_ELSE && $this->dependencytokens[1][0] !== T_IF) { $this->dependencytokens = $this->last_dependency; $this->dependencytokens[] = array(T_ELSE, 'else', $this->dependencytokens[0][2]); } } else { $this->ignore_requirement = false; } // add dependency (even push empty dependency on stack, it will get poped again) $this->dependencies[$line_nr] = $this->dependencytokens; $this->dependencytokens = array(); } else { unset($e); } $this->braces_open++; } else { if ($this->tokens[$i] === '}' && ($this->tokens[$i - 1] === ';' || $this->tokens[$i - 1] === '}' || $this->tokens[$i - 1] === '{')) { $this->braces_open--; // delete current dependency $this->last_dependency = array_pop($this->dependencies); $this->dependencytokens = array(); // end of function found if brace amount = amount before function start if ($this->in_function && $this->brace_save_func === $this->braces_open) { $ref_name = ($this->in_class ? $this->class_name . '::' : '') . $this->function_obj->name; // write ending to user_function list for referencing functions in output $GLOBALS['user_functions_offset'][$ref_name][2] = $line_nr; // reset vars for next function declaration $this->brace_save_func = -1; $this->ignore_securing_function = false; $this->in_function--; $this->function_obj = null; $this->var_declares_local = array(); $this->put_in_global_scope = array(); // load new found vulnerable user functions to current scanlist if (isset($GLOBALS['user_functions'][$this->file_name])) { $this->scan_functions = array_merge($this->scan_functions, $GLOBALS['user_functions'][$this->file_name]); } } // end of class found if ($this->in_class && $this->brace_save_class === $this->braces_open) { $this->brace_save_class = -1; $this->in_class = false; } } } } // token scanned // detect if still in a vardeclare, otherwise delete saved infos if (isset($vardeclare) && $vardeclare['end'] === $i) { unset($vardeclare); } } // all tokens scanned. return $this->inc_map; }
public function testAnalyzer() { $result = Analyzer::analyze("Guns are awesome"); dd($result); return "Testing functions"; }