Cloacking WordPress
Après l’installation, comment sécuriser son wordpress ?
2 axes;
- Premièrement rendre pénible la détection de la version et des plugins.
- Sécuriser les access admin.
Je repasserai pas sur le système, on part du principe vous maintenez L’Os, le WordPress, ses plugins, le php, l’apache et le MySQL à jours bien consciencieusement. Le tout bien sur avec un mot de passe qui n’est pas “toto”.
#OP Obfuscation
Passons à la phase “Obfuscation”. Histoire de gagner du temps quand une faille sortira. Il n’est pas rare que quelques margoulins maintiennent à jours des listes de sites utilisant WordPress et des plugins utilisés. Cela est fait pour utiliser les failles existantes, et préparer les futures exploitations dès que de nouvelles failles apparaitront. Pour détecter la version de WordPress, on va utiliser WP-Scan, un petit scanner de WordPress en ruby qui fonctionne à merveille.
Premier Scan :
thanat0s@cyanide:~/bin/wpscan$ ./wpscan.rb --url thanat0s.trollprod.org
[...SNIP...SNIP...]
WordPress Security Scanner by the WPScan Team
Sponsored by the RandomStorm Open Source Initiative
_____________________________________________________
| URL: http://thanat0s.trollprod.org/
| Started on Sat Sep 22 10:26:35 2012
[!] The WordPress theme in use is inferno-mf v1.2
[!] WordPress version 3.4.2 identified from readme.html
[+] Enumerating plugins from passive detection ... No plugins found :(
[+] Finished at Sat Sep 22 10:26:37 2012
Trop facile pour lui , il retrouve aisément tous les fichiers de readme et de version… nettoyons un peu notre installation..
- Virer les licences.txt qui incluent la version de wordpress
server:/www# find . -iname licence.txt -exec rm {} \;
- Virer le readme.html qui donne aussi la version
server:/www# rm readme.html
- Et en cas de plugins bavards…
server:/www# find . -iname readme.txt -exec rm {} \;
Et jusque là, ce que l’on a fait sert pas à grand choses, un bon tools comme wpscan n’est pas “fatigué pour autant”
Second scan :
thanat0s@cyanide:~/bin/wpscan$ ./wpscan.rb --url thanat0s.trollprod.org
[...SNIP...SNIP...]
WordPress Security Scanner by the WPScan Team
Sponsored by the RandomStorm Open Source Initiative
_____________________________________________________
| URL: http://thanat0s.trollprod.org/
| Started on Sat Sep 22 10:26:35 2012
[!] The WordPress theme in use is inferno-mf v1.2
[!] WordPress version 3.4.2 identified from meta generator
[+] Enumerating plugins from passive detection ... No plugins found :(
[+] Finished at Sat Sep 22 10:26:37 2012
Tabernacle ! Il trouve la version via le meta generator…On désactive ceci en squeezant le “add_action” qui va bien
server:/www # grep wp_generator * -R
wp-includes/default-filters.php:add_action( 'wp_head', 'wp_generator' );
wp-includes/general-template.php:function wp_generator() {
wp-includes/general-template.php: the_generator(apply_filters('wp_generator_type','xhtml'));
Dans mon cas, l’édition de default-filter.php et mise en commentaire de la ligne. Attention, on touche au CORE WordPress, il faudra probablement le refaire en cas d’upgrade de WordPress
Mais cela ne suffit toujours pas !
Troisième scan :
thanatos@cyanide:~/bin/wpscan# ./wpscan.rb --url thanat0s.trollprod.org
[...SNIP...SNIP...]
WordPress Security Scanner by the WPScan Team
Sponsored by the RandomStorm Open Source Initiative
_____________________________________________________
| URL: http://thanat0s.trollprod.org/
| Started on Sat Sep 22 10:59:09 2012
[!] The WordPress theme in use is inferno-mf v1.2
[!] WordPress version 3.4.2 identified from advanced fingerprinting
[+] Enumerating plugins from passive detection ... No plugins found :(
[+] Finished at Sat Sep 22 10:59:11 2012
L’acharné trouve maintenant la version via fingerprinting, Mais comment fait t’il ce saloptiot ? c’est simple mais malin. Il calcule le MD5 de certaines pages, JS, CSS etc… La liste des MD5 et des fichiers audité est là.
https://github.com/wpscanteam/wpscan/blob/master/data/wp_versions.xml
Mais le MD5 c’est magique, on change un seul charactère et ce n’est plus le même fichier. Allons y.
server:/www# for lines in `find . -iname *.js`; do echo " " >> $lines; done
server:/www# for lines in `find . -iname *.css`; do echo " " >> $lines; done
Dernier scan :
Scannons,
thanatos@cyanide:~/bin/wpscan/# ./wpscan.rb --url thanat0s.trollprod.org
[...SNIP...SNIP...]
WordPress Security Scanner by the WPScan Team
Sponsored by the RandomStorm Open Source Initiative
_____________________________________________________
| URL: http://thanat0s.trollprod.org/
| Started on Sat Sep 22 11:43:46 2012
[!] The WordPress theme in use is inferno-mf v1.2
[+] Enumerating plugins from passive detection ... No plugins found :(
[+] Finished at Sat Sep 22 11:43:50 2012
Et voila, il est enfin comme un con.. il reste certes la version du thème mais c’est généralement pas la fin du monde (Encore que certain thèmes amènent aussi des failles. Pour les puristes, Ce numéro de version est dans les commentaires des fichiers CSS).
Ce qui est plus génant c’est les plugins. Ce qui nous ammène au chapitre suivant.
#OP Calmer les hardeurs
WPScan dispose de 2 fonctions qui peuvent devenir génante.
- Le Bruteforce du compte admin.
- Le Bruteforce à la recherche des plugins installés.
Aux gens qui bruteforcent, la réponse sera sanglante, j’ai nommé Fail2Ban, ou comment transformer toutes tentative de bruteforcing en punition (Pour ceux qui ne savent pas, Fail2Ban est un daemon qui blacklist les IPs des clients contrevenants.).
On va voir après le fichier de configuration que j’utilise, il permet de bannir tout contrevenant qui tenterai de bruteforcer la page de login de l’admin ou la liste des plugins.
Voici a quoi ressemble un log de bruteforce, l’authentification étant faite par un formulaire html, au niveau des logs c’est une successions de POSTs qui terminent en code 200 (Rappel, 200 c’est le Code qui veut dire OK tout va bien, vla ta page). Rien ne nous permet de dire que le login s’est mal passé pour un hit. Le User-Agent est crédible mais la fréquence est anormale ! Un user ou un admin n’a pas à se logger 10 fois de suite en 2 minutes, et même si c’est un vrai utilisateur, manifestement il a les doigts carrés, il doit être raisonné !!
- 1.2.3.4 - - [23/Sep/2012:17:05:05 +0200] "POST /wp-login.php HTTP/1.1" 200 1326 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0"
- 1.2.3.4 - - [23/Sep/2012:17:05:06 +0200] "POST /wp-login.php HTTP/1.1" 200 1326 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0"
- 1.2.3.4 - - [23/Sep/2012:17:05:05 +0200] "POST /wp-login.php HTTP/1.1" 200 1326 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0"
- 1.2.3.4 - - [23/Sep/2012:17:05:06 +0200] "POST /wp-login.php HTTP/1.1" 200 1326 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0"
la simple recherche de la chaine “POST /wp-login.php” permettra de créer un rate limiteur sur la page de login.
Concernant les plugins, la détection qu’opère WP-Scan se fait aussi par bruteforce
- 1.2.3.4 - - [23/Sep/2012:17:05:05 +0200] "GET /wp-content/plugins/bluetrait-event-viewer/ HTTP/1.1" 404 632 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0"
- 1.2.3.4 - - [23/Sep/2012:17:05:05 +0200] "GET /wp-content/plugins/login-security-solution/ HTTP/1.1" 404 632 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0"
- 1.2.3.4 - - [23/Sep/2012:17:05:05 +0200] "GET /wp-content/plugins/better-wp-security/ HTTP/1.1" 404 632 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0"
- 1.2.3.4 - - [23/Sep/2012:17:05:05 +0200] "GET /wp-content/plugins/limit-login-attempts/ HTTP/1.1" 404 632 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0"
- 1.2.3.4 - - [23/Sep/2012:17:05:05 +0200] "GET /wp-content/plugins/simple-login-lockdown/ HTTP/1.1" 404 632 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0"
Là c’est déja plus simple. Si c’est un code 404 (Qui veut dire “Page not Found”) et dans le répertoire /wp-content/plugins … Ca pue !
Et voila donc la conf que l’on peut mettre en place pour calmer toute utilisation de WPScan avec Fail2Ban
Le fichier de “filtre” nommé wordpress.conf
# Fail2Ban configuration file
#
# Author: Thanat0S
#
# $Revision: 1$
[Definition]
#
# Option: failregex
# Notes.: regex to match the password failures messages in the logfile. The
# host must be matched by a group named "host". The tag "<HOST>" can
# be used for standard IP/hostname matching and is only an alias for
# (?:::f{4,6}:)?(?P<host>[\w\-.^_]+)
# Values: TEXT
#
failregex = [\-\S\.]+\s<HOST>.*(?:\/wp-content\/plugins\/.+\sHTTP\/[01]\.[019]\"\s404|POST\s\/wp-login\.php)
# Notes.: regex to ignore. If this regex matches, the line is ignored.
# Values: TEXT
#
ignoreregex =
Et dans le fichier jail.conf ajoutons le paragraphe suivant :
[wordpress]
enabled = true
filter = wordpress
action = iptables[name=wordpress, port=www, protocol=tcp]
sendmail-whois-lines[name=wordpress, dest=celuiquiseraprevenu@trollprod.org]
logpath = /var/log/laousont/leslogs.log
maxretry = 10
bantime = 900
findtime = 900
Voila qui donnera une bonne pénalité de 15mn à toutes personnes qui tentera d’utiliser WPScan pour lister les plugins ou bruteforcer votre compte admin. D’autant plus drole de WPScan ne gère pas très bien ce genre de punition et reste “coincé” sans lacher pendant tout le temps de la punition.
Et voila donc une installation qui devrait diriger le méchant hacker vers un autre WordPress que le votre, un peut être plus accessible. Bon… mais chiottes, maintenant on sait que j’ai WordPress 3.4.2 moi ! ;)