PluginProbe
WebTotem Security / 3.0.1
WebTotem Security v3.0.1
3.0.1 3.0.0 trunk 1.0 1.1 1.2 1.3 1.3.1 1.3.2 1.3.3 2.0 2.1 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.1 2.2.2 2.2.3 2.2.4 All 109 releases
wt-security / lib / modules / login / BFProtection.php

BFProtection.php in WebTotem Security 3.0.1, at lib/modules/login/BFProtection.php

210 lines 7.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('WEBTOTEM_INIT') || WEBTOTEM_INIT !== true) {
4 if (!headers_sent()) {
5 header('HTTP/1.1 403 Forbidden');
6 }
7 die("Protected By WebTotem!");
8 }
9 /**
10 * WebTotem bruteforce protection class for Wordpress.
11 */
12 class WebTotemBFProtection{
13
14 /**
15 * Check brute force attempts.
16 *
17 * @param WP_User $user
18 * WP_User.
19 *
20 * @return mixed
21 */
22 public static function checkBruteForceAttempts( $user, $username ) {
23 $ip = WebTotem::getUserIP();
24 $login_attempts_enabled = WebTotemOption::getPluginSettings('login_attempts');
25 $errorCodes = [
26 'invalid_username',
27 'invalid_email',
28 'incorrect_password',
29 'twofactor_invalid',
30 'authentication_failed',
31 'wtotem_two_factor_failed',
32 ];
33
34 if($login_attempts_enabled){
35
36 $message = sprintf( __('Exceeded the maximum number of login failures which is: %1$s.', 'wtotem'), WebTotemOption::getPluginSettings('login_number_of_attempts'));
37
38 if(self::isIpBlocked($ip, 'login')){
39 return new \WP_Error('wtotem_login_failure', $message);
40 }
41
42 $temp_option = self::getTempLogin($ip);
43 if(is_wp_error($user) && in_array($user->get_error_code(), $errorCodes)) {
44 $tries = get_transient($temp_option);
45 if($tries){
46 $tries++;
47 } else {
48 $tries = 1;
49 }
50 if($tries >= WebTotemOption::getPluginSettings('login_number_of_attempts')){
51 self::lockOutIp($ip, 'login');
52 return new \WP_Error('wtotem_login_failure', $message);
53 }
54 set_transient($temp_option, $tries, 60);
55 } else if(is_object($user) && get_class($user) == 'WP_User'){
56 delete_transient($temp_option); //reset counter on success
57 }
58 }
59
60 if(is_wp_error($user) && ($user->get_error_code() == 'invalid_username' || $user->get_error_code() == 'invalid_email' || $user->get_error_code() == 'incorrect_password') ){
61 return new \WP_Error( 'incorrect_password', sprintf( wp_kses(__( '<strong>ERROR</strong>: The username or password you entered is incorrect. <a href="%2$s" title="Password Lost and Found">Lost your password</a>?', 'wordfence' ), array('strong'=>array(), 'a'=>array('href'=>array(), 'title'=>array()))), $username, wp_lostpassword_url() ) );
62 }
63 return $user;
64 }
65
66 /**
67 * Check reset password attempts
68 *
69 * @return mixed
70 */
71 public static function lostPassword($errors) {
72 $ip = WebTotem::getUserIP();
73 $password_reset_number_of_attempts = WebTotemOption::getPluginSettings('password_reset_number_of_attempts');
74 $message = sprintf( __('Exceeded the maximum number of tries to recover their password which is set at: %1$s', 'wtotem'), $password_reset_number_of_attempts);
75
76 if(self::isIpBlocked($ip, 'lost_password')){
77 $errors = new \WP_Error('wtotem_lost_password_failure', $message);
78 }
79
80 $password_reset_attempts_enabled = WebTotemOption::getPluginSettings('password_reset');
81 if($password_reset_attempts_enabled){
82 $temp_option = self::getTempLostPass($ip);
83 $tries = get_transient($temp_option);
84 if($tries){
85 $tries++;
86 } else {
87 $tries = 1;
88 }
89 if($tries >= WebTotemOption::getPluginSettings('password_reset_number_of_attempts')){
90 self::lockOutIp($ip, 'lost_password');
91 $errors = new \WP_Error('wtotem_lost_password_failure', $message);
92 }
93 set_transient($temp_option, $tries, 60);
94 }
95
96 return $errors;
97 }
98
99 /**
100 * Lock out IP.
101 *
102 * @param string $ip
103 * User IP.
104 * @param string $reason
105 *
106 */
107 public static function lockOutIp($ip, $reason) {
108 $blockedTime = time() + WebTotemOption::getPluginSettings('login_minutes_of_ban') * 60;
109 WebTotemDB::setData(['ip' => $ip, 'reason' => $reason, 'blockedTime' => $blockedTime], 'blocked_list');
110 }
111
112 /**
113 * Check if the IP is blocked.
114 *
115 * @param string $ip
116 * User IP.
117 * @param string $reason
118 *
119 */
120 public static function isIpBlocked($ip, $reason) {
121 $data = WebTotemDB::getData(['ip' => $ip, 'reason' => $reason], 'blocked_list');
122
123 if( $data ){
124 if(time() > $data['blockedTime']){
125 WebTotemDB::deleteData(['id' => $data['id']],'blocked_list');
126 } else {
127 return true;
128 }
129 }
130
131 return false;
132 }
133
134 public static function getTempLogin($ip) {
135 return 'wtotem_tl_' . bin2hex(self::encodeIpToBinary($ip));
136 }
137
138 public static function getTempLostPass($ip) {
139 return 'wtotem_tlp_' . bin2hex(self::encodeIpToBinary($ip));
140 }
141
142 /**
143 * Return the packed binary string of an IPv4 or IPv6 address.
144 *
145 * @param string $ip
146 * @return string
147 */
148 public static function encodeIpToBinary($ip) {
149 // convert the 4 char IPv4 to IPv6 mapped version.
150 $pton = str_pad(self::supportsIPv6() ? @inet_pton($ip) : self::compatIpCompression($ip), 16,
151 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00", STR_PAD_LEFT);
152 return $pton;
153 }
154
155 /**
156 * Check PHP was compiled with IPv6 support.
157 *
158 * @return bool
159 */
160 public static function supportsIPv6() {
161 return defined('AF_INET6');
162 }
163
164 /**
165 * Added compatibility for hosts that do not have inet_pton.
166 *
167 * @param $ip
168 * @return bool|string
169 */
170 public static function compatIpCompression($ip) {
171 // IPv4
172 if (preg_match('/^(?:\d{1,3}(?:\.|$)){4}/', $ip)) {
173 $octets = explode('.', $ip);
174 $bin = chr($octets[0]) . chr($octets[2]) . chr($octets[3]);
175 return $bin;
176 }
177
178 // IPv6
179 if (preg_match('/^((?:[\da-f]{1,4}(?::|)){0,8})(::)?((?:[\da-f]{1,4}(?::|)){0,8})$/i', $ip)) {
180 if ($ip === '::') {
181 return "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
182 }
183 $colon_count = substr_count($ip, ':');
184 $dbl_colon_pos = strpos($ip, '::');
185 if ($dbl_colon_pos !== false) {
186 $ip = str_replace('::', str_repeat(':0000',
187 (($dbl_colon_pos === 0 || $dbl_colon_pos === strlen($ip) - 2) ? 9 : 8) - $colon_count) . ':', $ip);
188 $ip = trim($ip, ':');
189 }
190
191 $ip_groups = explode(':', $ip);
192 $ipv6_bin = '';
193 foreach ($ip_groups as $ip_group) {
194 $ipv6_bin .= pack('H*', str_pad($ip_group, 4, '0', STR_PAD_LEFT));
195 }
196
197 return strlen($ipv6_bin) === 16 ? $ipv6_bin : false;
198 }
199
200 // IPv4 mapped IPv6
201 if (preg_match('/^(?:\:(?:\:0{1,4}){0,4}\:|(?:0{1,4}\:){5})ffff\:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/i', $ip, $matches)) {
202 $octets = explode('.', $matches[1]);
203 return "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" . chr($octets[0]) . chr($octets[1]) . chr($octets[2]) . chr($octets[3]);
204 }
205
206 return false;
207 }
208
209 }
210