PluginProbe
WebTotem Security / 2.4.14
WebTotem Security v2.4.14
3.0.2 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 All 110 releases
wt-security / lib / login / BFProtection.php

BFProtection.php in WebTotem Security 2.4.14, at lib/login/BFProtection.php

214 lines 7.5 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 ) {
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 /** TODO Log entry of authorization attempts */
61
62 if(is_wp_error($user) && ($user->get_error_code() == 'invalid_username' || $user->get_error_code() == 'invalid_email' || $user->get_error_code() == 'incorrect_password') ){
63 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() ) );
64 }
65 return $user;
66 }
67
68 /**
69 * Check reset password attempts
70 *
71 * @return mixed
72 */
73 public static function lostPassword($errors) {
74 $ip = WebTotem::getUserIP();
75 $password_reset_number_of_attempts = WebTotemOption::getPluginSettings('password_reset_number_of_attempts');
76 $message = sprintf( __('Exceeded the maximum number of tries to recover their password which is set at: %1$s', 'wtotem'), $password_reset_number_of_attempts);
77
78 if(self::isIpBlocked($ip, 'lost_password')){
79 $errors = new \WP_Error('wtotem_lost_password_failure', $message);
80 }
81
82 /** TODO Log entry of password reset attempts */
83
84 $password_reset_attempts_enabled = WebTotemOption::getPluginSettings('password_reset');
85 if($password_reset_attempts_enabled){
86 $temp_option = self::getTempLostPass($ip);
87 $tries = get_transient($temp_option);
88 if($tries){
89 $tries++;
90 } else {
91 $tries = 1;
92 }
93 if($tries >= WebTotemOption::getPluginSettings('password_reset_number_of_attempts')){
94 self::lockOutIp($ip, 'lost_password');
95 $errors = new \WP_Error('wtotem_lost_password_failure', $message);
96 }
97 set_transient($temp_option, $tries, 60);
98 }
99
100 return $errors;
101 }
102
103 /**
104 * Lock out IP.
105 *
106 * @param string $ip
107 * User IP.
108 * @param string $reason
109 *
110 */
111 public static function lockOutIp($ip, $reason) {
112 $blockedTime = time() + WebTotemOption::getPluginSettings('login_minutes_of_ban') * 60;
113 WebTotemDB::setData(['ip' => $ip, 'reason' => $reason, 'blockedTime' => $blockedTime], 'blocked_list');
114 }
115
116 /**
117 * Check if the IP is blocked.
118 *
119 * @param string $ip
120 * User IP.
121 * @param string $reason
122 *
123 */
124 public static function isIpBlocked($ip, $reason) {
125 $data = WebTotemDB::getData(['ip' => $ip, 'reason' => $reason], 'blocked_list');
126
127 if( $data ){
128 if(time() > $data['blockedTime']){
129 WebTotemDB::deleteData(['id' => $data['id']],'blocked_list');
130 } else {
131 return true;
132 }
133 }
134
135 return false;
136 }
137
138 public static function getTempLogin($ip) {
139 return 'wtotem_tl_' . bin2hex(self::inet_pton($ip));
140 }
141
142 public static function getTempLostPass($ip) {
143 return 'wtotem_tlp_' . bin2hex(self::inet_pton($ip));
144 }
145
146 /**
147 * Return the packed binary string of an IPv4 or IPv6 address.
148 *
149 * @param string $ip
150 * @return string
151 */
152 public static function inet_pton($ip) {
153 // convert the 4 char IPv4 to IPv6 mapped version.
154 $pton = str_pad(self::hasIPv6Support() ? @inet_pton($ip) : self::_inet_pton($ip), 16,
155 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00", STR_PAD_LEFT);
156 return $pton;
157 }
158
159 /**
160 * Check PHP was compiled with IPv6 support.
161 *
162 * @return bool
163 */
164 public static function hasIPv6Support() {
165 return defined('AF_INET6');
166 }
167
168 /**
169 * Added compatibility for hosts that do not have inet_pton.
170 *
171 * @param $ip
172 * @return bool|string
173 */
174 public static function _inet_pton($ip) {
175 // IPv4
176 if (preg_match('/^(?:\d{1,3}(?:\.|$)){4}/', $ip)) {
177 $octets = explode('.', $ip);
178 $bin = chr($octets[0]) . chr($octets[1]) . chr($octets[2]) . chr($octets[3]);
179 return $bin;
180 }
181
182 // IPv6
183 if (preg_match('/^((?:[\da-f]{1,4}(?::|)){0,8})(::)?((?:[\da-f]{1,4}(?::|)){0,8})$/i', $ip)) {
184 if ($ip === '::') {
185 return "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
186 }
187 $colon_count = substr_count($ip, ':');
188 $dbl_colon_pos = strpos($ip, '::');
189 if ($dbl_colon_pos !== false) {
190 $ip = str_replace('::', str_repeat(':0000',
191 (($dbl_colon_pos === 0 || $dbl_colon_pos === strlen($ip) - 2) ? 9 : 8) - $colon_count) . ':', $ip);
192 $ip = trim($ip, ':');
193 }
194
195 $ip_groups = explode(':', $ip);
196 $ipv6_bin = '';
197 foreach ($ip_groups as $ip_group) {
198 $ipv6_bin .= pack('H*', str_pad($ip_group, 4, '0', STR_PAD_LEFT));
199 }
200
201 return strlen($ipv6_bin) === 16 ? $ipv6_bin : false;
202 }
203
204 // IPv4 mapped IPv6
205 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)) {
206 $octets = explode('.', $matches[1]);
207 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]);
208 }
209
210 return false;
211 }
212
213 }
214