WordPress login form and Pipal
I manage a number of WordPress sites. These sites get a lot of login attempts. Instead of dropping these attempts I decided to log them and build some stats.
I also wanted “something” that I could use to play with Pipal. Pipal is a password analyzer that provides useful statistics on a list of passwords. Note that it is NOT a password cracker.
I created a fake WordPress login form (wp-login.php) and installed this on a number of un-used domains. These domains all point to the same template location. Every connection to any of these domains is suspicious (or at least unusual) because there’s nothing to be found at these URLs.
You can easily recreate a version of wp-login.php on your own. Go to a normal WordPress login page and save the HTML. Then strip the calls for external files (CSS, Javascript, …) and include the necessary CSS inline.
I added one hidden HTML form field (called ‘testcookie’).
<p class="submit"> <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="Log In" /> <input type="hidden" name="redirect_to" value="wp-login.php" /> <input type="hidden" name="testcookie" value="1" /> </p>
I then extract timestamp, source IP, browser identification, username and password from the POST submit.
$record = $time . " - " . $ip . " - log: " . $log . " - pwd: " . $pwd . " - testcookie: " . $testcookie . " - browser: " . $browser;
Submitted credentials
Between 31-Oct-2014 and 12-Dec-2014 there were 36163 submits.
Network sources
75% percent of the requests came from one AS in the United Kingdom.
Form test cookie or not?
Out of the 36163 requests, 782 requests had the form test cookie set. These requests came from different sources but all had the same browser identification (see below for the browser id with 782 requests). The timing makes it very unlikely that these were manual requests (multiple attempts per second).
Based on the timing, the different network sources and a similar request type I assume these were made with the same tool(kit). I could not find any other requests (GET or POST) from these IPs in the logs, meaning that the submit is done regardless if there’s a WordPress form or not.
Browser identification
The bulk of the requests did not had a browser identification set. The Firefox browser “USA\Miami Style” was used by different network sources.
Usernames
The list of usernames did not contain any surprises. Two types of submits (6920 and 6812 times) contained the full domain (www.domain.be or domain.be) as the username. I replaced the actual name by “domain.be” in the result below.
Password analysis with Pipal
Pipal is a password analyzer, you can get it from Github. It needs Ruby 1.9.x but requires no other dependencies.
./pipal.rb wp-login-attempts-PASSWORDS
Generating stats, hit CTRL-C to finish early and dump stats on words already processed. Please wait... Processing: 100% |oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo| Time: 00:00:02 Basic Results Total entries = 36163 Total unique entries = 10179 Top 10 passwords admin = 55 (0.15%) 123456 = 55 (0.15%) 12345678 = 51 (0.14%) pass = 50 (0.14%) 123 = 49 (0.14%) 1234 = 49 (0.14%) password = 49 (0.14%) 12345 = 48 (0.13%) test = 46 (0.13%) 111111 = 46 (0.13%) Top 10 base words admin = 254 (0.7%) qwerty = 161 (0.45%) password = 153 (0.42%) test = 98 (0.27%) pass = 93 (0.26%) qwer = 83 (0.23%) qweasdzxc = 57 (0.16%) administrator = 51 (0.14%) qwert = 50 (0.14%) abcd = 48 (0.13%) Password length (length ordered) 1 = 108 (0.3%) 2 = 64 (0.18%) 3 = 310 (0.86%) 4 = 3107 (8.59%) 5 = 3266 (9.03%) 6 = 11588 (32.04%) 7 = 6754 (18.68%) 8 = 7729 (21.37%) 9 = 1417 (3.92%) 10 = 724 (2.0%) 11 = 290 (0.8%) 12 = 334 (0.92%) 13 = 122 (0.34%) 14 = 80 (0.22%) 15 = 107 (0.3%) 16 = 47 (0.13%) 17 = 32 (0.09%) 18 = 15 (0.04%) 19 = 13 (0.04%) 20 = 8 (0.02%) 21 = 8 (0.02%) 22 = 8 (0.02%) 23 = 8 (0.02%) 24 = 16 (0.04%) 27 = 8 (0.02%) Password length (count ordered) 6 = 11588 (32.04%) 8 = 7729 (21.37%) 7 = 6754 (18.68%) 5 = 3266 (9.03%) 4 = 3107 (8.59%) 9 = 1417 (3.92%) 10 = 724 (2.0%) 12 = 334 (0.92%) 3 = 310 (0.86%) 11 = 290 (0.8%) 13 = 122 (0.34%) 1 = 108 (0.3%) 15 = 107 (0.3%) 14 = 80 (0.22%) 2 = 64 (0.18%) 16 = 47 (0.13%) 17 = 32 (0.09%) 24 = 16 (0.04%) 18 = 15 (0.04%) 19 = 13 (0.04%) 20 = 8 (0.02%) 21 = 8 (0.02%) 22 = 8 (0.02%) 23 = 8 (0.02%) 27 = 8 (0.02%) | | | | | | | ||| ||| ||| ||| ||| ||||| ||||| ||||| |||||| |||||||||||||||||||||||||||| 0000000000111111111122222222 0123456789012345678901234567 One to six characters = 18443 (51.0%) One to eight characters = 32926 (91.05'%) More than eight characters = 3237 (8.95%) Only lowercase alpha = 25960 (71.79%) Only uppercase alpha = 33 (0.09%) Only alpha = 25993 (71.88%) Only numeric = 4043 (11.18%) First capital last symbol = 16 (0.04%) First capital last number = 113 (0.31%) Single digit on the end = 2556 (7.07%) Two digits on the end = 441 (1.22%) Three digits on the end = 935 (2.59%) Last number 0 = 600 (1.66%) 1 = 2855 (7.89%) 2 = 748 (2.07%) 3 = 1394 (3.85%) 4 = 585 (1.62%) 5 = 533 (1.47%) 6 = 539 (1.49%) 7 = 425 (1.18%) 8 = 370 (1.02%) 9 = 495 (1.37%) | | | | | | | | | | | | | | ||| ||||| | |||||||||| |||||||||| |||||||||| 0123456789 Last digit 1 = 2855 (7.89%) 3 = 1394 (3.85%) 2 = 748 (2.07%) 0 = 600 (1.66%) 4 = 585 (1.62%) 6 = 539 (1.49%) 5 = 533 (1.47%) 9 = 495 (1.37%) 7 = 425 (1.18%) 8 = 370 (1.02%) Last 2 digits (Top 10) 23 = 956 (2.64%) 12 = 253 (0.7%) 34 = 250 (0.69%) 11 = 244 (0.67%) 21 = 209 (0.58%) 56 = 199 (0.55%) 00 = 170 (0.47%) 45 = 154 (0.43%) 89 = 122 (0.34%) 66 = 112 (0.31%) Last 3 digits (Top 10) 123 = 912 (2.52%) 234 = 225 (0.62%) 456 = 174 (0.48%) 321 = 166 (0.46%) 111 = 148 (0.41%) 345 = 125 (0.35%) 000 = 112 (0.31%) 789 = 97 (0.27%) 666 = 71 (0.2%) 555 = 61 (0.17%) Last 4 digits (Top 10) 1234 = 213 (0.59%) 3456 = 136 (0.38%) 2345 = 125 (0.35%) 1111 = 103 (0.28%) 6789 = 76 (0.21%) 4321 = 76 (0.21%) 3123 = 61 (0.17%) 5678 = 60 (0.17%) 2222 = 55 (0.15%) 7890 = 54 (0.15%) Last 5 digits (Top 10) 23456 = 136 (0.38%) 12345 = 125 (0.35%) 11111 = 94 (0.26%) 56789 = 71 (0.2%) 54321 = 62 (0.17%) 23123 = 57 (0.16%) 45678 = 55 (0.15%) 67890 = 50 (0.14%) 23321 = 49 (0.14%) 55555 = 48 (0.13%) Character sets loweralpha: 25960 (71.79%) loweralphanum: 5198 (14.37%) numeric: 4043 (11.18%) loweralphaspecial: 200 (0.55%) loweralphaspecialnum: 190 (0.53%) mixedalphanum: 144 (0.4%) mixedalpha: 128 (0.35%) special: 58 (0.16%) specialnum: 46 (0.13%) mixedalphaspecialnum: 34 (0.09%) upperalpha: 33 (0.09%) upperalphaspecial: 17 (0.05%) mixedalphaspecial: 12 (0.03%) Character set ordering allstring: 26121 (72.23%) alldigit: 4043 (11.18%) stringdigit: 4041 (11.17%) othermask: 830 (2.3%) digitstring: 465 (1.29%) stringdigitstring: 243 (0.67%) stringspecialstring: 163 (0.45%) digitstringdigit: 77 (0.21%) stringspecialdigit: 72 (0.2%) allspecial: 58 (0.16%) stringspecial: 34 (0.09%) specialstring: 12 (0.03%) specialstringspecial: 4 (0.01%)
thanks for sharing. I enjoyed this one a great deal. Maybe we shouldn’t tell user how to chose passwords based on our assumptions what is complex/difficult to bruteforce but more based on the analysis what actual attackers are doing