A raíz del post "Listar los plugins de WordPress" en "Un informático en el lado del mal", vamos a ver una configuración de Apache que evite revelar la presencia de los plugins y otras opciones.
La configuración del VirtualHost debería ser similar a la siguiente, recortando algunas partes irrelevantes:
<VirtualHost *:80>
ServerAdmin webmaster@dummy-host.example.com
DocumentRoot "/var/www/blog/htdocs/"
ServerName systemadmin.es
DirectoryIndex index.php
<Directory /var/www/blog/htdocs/>
Options FollowSymLinks
AllowOverride None
Order deny,allow
Allow from all
</Directory>
<Files wp-login.php>
Order Deny,Allow
Allow from 1.2.3.4
Deny from All
</Files>
<Directory /var/www/blog/htdocs/wp-admin>
Options FollowSymLinks
AllowOverride None
Order Deny,Allow
Allow from 1.2.3.4
Deny from All
</Directory>
<Filesmatch ^wp-config.php$>
Deny from all
</Filesmatch>
<Directory /var/www/blog/htdocs/wp-content/plugins>
DirectorySlash Off
</Directory>
RewriteEngine On
RewriteCond %{REQUEST_URI} !/(about|wp-includes|wp-content|images|wp-admin|wp-login)/
RewriteCond %{REQUEST_URI} !/(about|google|sitemap|wp-comments-post.php|wp-login.php|favicon.ico|xmlrpc.php|buscador.xml)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</VirtualHost>
Las partes importantes son:
Deshabilitar mod_autoindex: Se trata de un modulo de Apache para hacer listados del contenido de los directorios.
Personalmente prefiero eliminar dicho modulo de apache al instalarlo mediante la opción de configure –disable-autoindex. Podemos comprobar si esta cargado el modulo mediante httpd -M:
# /usr/local/apache22/bin/httpd -M | grep index
Syntax OK
Deshabilitar el .htaccess: Independientemente por la perdida de rendimiento que supone el htaccess, supone un riesgo permitir que un fichero pueda modificar la configuración de apache, por esto lo deshabilitamos mediante:
AllowOverride None
La configuración que tengamos en el .htaccess la deberemos mover a la configuración del VirtualHost. Típicamente los rewrites, a los que deberemos añadir la siguiente regla antes de cualquier RewriteCond o RewriteRule:
RewriteEngine On
Restricciones por IP en wp-login.php y wp-admin: En el caso que sea un blog personal lo podemos limitar a nuestra IP o si la tenemos dinámica siempre podemos usar OpenVPN para restringir el acceso, además de cifrar las comunicaciones. En la configuración de Apache indicamos mediante el Allow que IPs permitimos:
Order Deny,Allow
Allow from 1.2.3.4
Deny from All
Proteger archivos sensibles como por ejemplo el wp-config.php: Los ficheros con configuración del blog, por ejemplo los datos de conexión al MySQL no son nunca servidos, sino que se leen desde otro PHP. Así, podemos denegar que sean servidos.
En condiciones normales, aunque sean servidos por el Apache, sería una página en blanco pero en el caso que falle el modulo de PHP (o exista un error en al configuración del Apache referente al PHP) se podría servir el contenido del fichero sin ejecutar. Esto pasó, ya hace años, a un proveedor de alojamiento gratuito muy conocido en España publicándose un montón de contraseñas.
La configuración que evita que dicho fichero sea servido es:
<Filesmatch ^wp-config.php$>
Deny from all
</Filesmatch>
Evitar la detección de plugins de WordPress mediante el script http-wp-plugins para nmap. Sin añadir ninguna opción adicional no detecta los plugins ya que en el script vemos lo siguiente:
local target
if wp_root then
-- Give user-supplied argument the priority
target = wp_root .. "/wp-content/plugins/" .. line .. "/"
elseif wp_autoroot then
-- Maybe the script has discovered another WordPress content directory
target = wp_autoroot .. "wp-content/plugins/" .. line .. "/"
else
-- Default WP directory is root
target = "/wp-content/plugins/" .. line .. "/"
end
Realiza una búsqueda del nombre del plugin seguido de una barra, dando siempre 404. Pero el modulo mod_dir si que añade una diferencia que permite detectar si un directorio existe. Por defecto, si el directorio existe pero no le hemos añadido una barra final hace un redirect al directorio con la barra:
# curl -I systemadmin.es/wp-content/plugins/akismet
HTTP/1.1 301 Moved Permanently
Date: Mon, 04 Jul 2011 19:55:28 GMT
Server: Apache
Location: http://systemadmin.es:81/wp-content/plugins/akismet/
Vary: Accept-Encoding
Content-Type: text/html; charset=iso-8859-1
# curl -I systemadmin.es/wp-content/plugins/akismet/
HTTP/1.1 404 Not Found
Date: Mon, 04 Jul 2011 19:55:30 GMT
Server: Apache
Vary: Accept-Encoding
Content-Type: text/html; charset=iso-8859-1
Por el contrario, si el directorio no existe no realiza este redirect:
# curl -I systemadmin.es/wp-content/plugins/noexisto_luego_existo
HTTP/1.1 404 Not Found
Date: Mon, 04 Jul 2011 19:55:34 GMT
Server: Apache
Vary: Accept-Encoding
Content-Type: text/html; charset=iso-8859-1
# curl -I systemadmin.es/wp-content/plugins/noexisto_luego_existo/
HTTP/1.1 404 Not Found
Date: Mon, 04 Jul 2011 19:55:36 GMT
Server: Apache
Vary: Accept-Encoding
Content-Type: text/html; charset=iso-8859-1
Lo que evita que para esta configuración sean detectados los plugins. Pero si modificamos el plugin de nmap para que no incluya la barra final si que los podremos detectar con el mismo diccionario:
local target
if wp_root then
-- Give user-supplied argument the priority
target = wp_root .. "/wp-content/plugins/" .. line
elseif wp_autoroot then
-- Maybe the script has discovered another WordPress content directory
target = wp_autoroot .. "wp-content/plugins/" .. line
else
-- Default WP directory is root
target = "/wp-content/plugins/" .. line
end
Con esta modificación podremos ver como sí que encuentra los plugins instalados dentro del directorio plugins (que no significa que esten habilitados):
$ nmap -p80 --script=http-wp-plugins --script-arg 'http-wp-plugins.root="/",http-wp-plugins.search=all' systemadmin.es
Starting Nmap 5.59BETA1 ( http://nmap.org ) at 2011-07-04 19:41 CEST
Nmap scan report for systemadmin.es (87.98.227.154)
Host is up (0.044s latency).
rDNS record for 87.98.227.154: jordi.prats.systemadmin.es
PORT STATE SERVICE
80/tcp open http
| http-wp-plugins:
| search amongst the 14170 most popular plugins
(...)
| akismet
(...)
Nmap done: 1 IP address (1 host up) scanned in 62.73 seconds
Esta característica que hace detectables los plugins la podemos deshabilitar mediante la opción DirectorySlash. Por lo que podemos añadirla exclusivamente para el directorio de plugins con:
<Directory /var/www/systemadmin.es/htdocs/wp-content/plugins>
DirectorySlash Off
</Directory>
Una vez aplicados los cambios en el Apache podremos comprobar como el redirect ha desaparecido, comportándose igual con un directorio que existe:
# curl -I systemadmin.es/wp-content/plugins/akismet
HTTP/1.1 404 Not Found
Date: Mon, 04 Jul 2011 19:59:46 GMT
Server: Apache
Vary: Accept-Encoding
Content-Type: text/html; charset=iso-8859-1
# curl -I systemadmin.es/wp-content/plugins/akismet/
HTTP/1.1 404 Not Found
Date: Mon, 04 Jul 2011 19:59:49 GMT
Server: Apache
Vary: Accept-Encoding
Content-Type: text/html; charset=iso-8859-1
Que con uno que no existe:
# curl -I systemadmin.es/wp-content/plugins/noexisto_luego_existo
HTTP/1.1 404 Not Found
Date: Mon, 04 Jul 2011 19:59:53 GMT
Server: Apache
Vary: Accept-Encoding
Content-Type: text/html; charset=iso-8859-1
# curl -I systemadmin.es/wp-content/plugins/noexisto_luego_existo/
HTTP/1.1 404 Not Found
Date: Mon, 04 Jul 2011 19:59:54 GMT
Server: Apache
Vary: Accept-Encoding
Content-Type: text/html; charset=iso-8859-1
Por lo que dicho script ya no detecta que plugins de WordPress están instalados:
$ nmap -p80 --script=http-wp-plugins --script-arg 'http-wp-plugins.root="/",http-wp-plugins.search=all' systemadmin.es
Starting Nmap 5.59BETA1 ( http://nmap.org ) at 2011-07-04 20:03 CEST
Nmap scan report for systemadmin.es (87.98.227.154)
Host is up (0.038s latency).
rDNS record for 87.98.227.154: jordi.prats.systemadmin.es
PORT STATE SERVICE
80/tcp open http
|_http-wp-plugins: nothing found amongst the 14170 most popular plugins, use --script-arg http-wp-plugins.search=<number|all> for deeper analysis)
Nmap done: 1 IP address (1 host up) scanned in 62.83 seconds
Evidentemente, si el diccionario se modificara para buscar ficheros que deben estar presentes en el caso que el plugin este instalado (ficheros de estilo, imagenes...) esto no serviría de nada.
Gracias a estas modificaciones en la configuración del VirtualHost de Apache complicaremos un poco más la identificación y explotación de vulnerabilidades, con la esperanza que se busquen un objetivo más fácil.
Fuente:
http://systemadmin.es/2011/07/configuracion-segura-de-apache-para-wordpress
La configuración del VirtualHost debería ser similar a la siguiente, recortando algunas partes irrelevantes:
<VirtualHost *:80>
ServerAdmin webmaster@dummy-host.example.com
DocumentRoot "/var/www/blog/htdocs/"
ServerName systemadmin.es
DirectoryIndex index.php
<Directory /var/www/blog/htdocs/>
Options FollowSymLinks
AllowOverride None
Order deny,allow
Allow from all
</Directory>
<Files wp-login.php>
Order Deny,Allow
Allow from 1.2.3.4
Deny from All
</Files>
<Directory /var/www/blog/htdocs/wp-admin>
Options FollowSymLinks
AllowOverride None
Order Deny,Allow
Allow from 1.2.3.4
Deny from All
</Directory>
<Filesmatch ^wp-config.php$>
Deny from all
</Filesmatch>
<Directory /var/www/blog/htdocs/wp-content/plugins>
DirectorySlash Off
</Directory>
RewriteEngine On
RewriteCond %{REQUEST_URI} !/(about|wp-includes|wp-content|images|wp-admin|wp-login)/
RewriteCond %{REQUEST_URI} !/(about|google|sitemap|wp-comments-post.php|wp-login.php|favicon.ico|xmlrpc.php|buscador.xml)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</VirtualHost>
Las partes importantes son:
Deshabilitar mod_autoindex: Se trata de un modulo de Apache para hacer listados del contenido de los directorios.
Personalmente prefiero eliminar dicho modulo de apache al instalarlo mediante la opción de configure –disable-autoindex. Podemos comprobar si esta cargado el modulo mediante httpd -M:
# /usr/local/apache22/bin/httpd -M | grep index
Syntax OK
Deshabilitar el .htaccess: Independientemente por la perdida de rendimiento que supone el htaccess, supone un riesgo permitir que un fichero pueda modificar la configuración de apache, por esto lo deshabilitamos mediante:
AllowOverride None
La configuración que tengamos en el .htaccess la deberemos mover a la configuración del VirtualHost. Típicamente los rewrites, a los que deberemos añadir la siguiente regla antes de cualquier RewriteCond o RewriteRule:
RewriteEngine On
Restricciones por IP en wp-login.php y wp-admin: En el caso que sea un blog personal lo podemos limitar a nuestra IP o si la tenemos dinámica siempre podemos usar OpenVPN para restringir el acceso, además de cifrar las comunicaciones. En la configuración de Apache indicamos mediante el Allow que IPs permitimos:
Order Deny,Allow
Allow from 1.2.3.4
Deny from All
Proteger archivos sensibles como por ejemplo el wp-config.php: Los ficheros con configuración del blog, por ejemplo los datos de conexión al MySQL no son nunca servidos, sino que se leen desde otro PHP. Así, podemos denegar que sean servidos.
En condiciones normales, aunque sean servidos por el Apache, sería una página en blanco pero en el caso que falle el modulo de PHP (o exista un error en al configuración del Apache referente al PHP) se podría servir el contenido del fichero sin ejecutar. Esto pasó, ya hace años, a un proveedor de alojamiento gratuito muy conocido en España publicándose un montón de contraseñas.
La configuración que evita que dicho fichero sea servido es:
<Filesmatch ^wp-config.php$>
Deny from all
</Filesmatch>
Evitar la detección de plugins de WordPress mediante el script http-wp-plugins para nmap. Sin añadir ninguna opción adicional no detecta los plugins ya que en el script vemos lo siguiente:
local target
if wp_root then
-- Give user-supplied argument the priority
target = wp_root .. "/wp-content/plugins/" .. line .. "/"
elseif wp_autoroot then
-- Maybe the script has discovered another WordPress content directory
target = wp_autoroot .. "wp-content/plugins/" .. line .. "/"
else
-- Default WP directory is root
target = "/wp-content/plugins/" .. line .. "/"
end
Realiza una búsqueda del nombre del plugin seguido de una barra, dando siempre 404. Pero el modulo mod_dir si que añade una diferencia que permite detectar si un directorio existe. Por defecto, si el directorio existe pero no le hemos añadido una barra final hace un redirect al directorio con la barra:
# curl -I systemadmin.es/wp-content/plugins/akismet
HTTP/1.1 301 Moved Permanently
Date: Mon, 04 Jul 2011 19:55:28 GMT
Server: Apache
Location: http://systemadmin.es:81/wp-content/plugins/akismet/
Vary: Accept-Encoding
Content-Type: text/html; charset=iso-8859-1
# curl -I systemadmin.es/wp-content/plugins/akismet/
HTTP/1.1 404 Not Found
Date: Mon, 04 Jul 2011 19:55:30 GMT
Server: Apache
Vary: Accept-Encoding
Content-Type: text/html; charset=iso-8859-1
Por el contrario, si el directorio no existe no realiza este redirect:
# curl -I systemadmin.es/wp-content/plugins/noexisto_luego_existo
HTTP/1.1 404 Not Found
Date: Mon, 04 Jul 2011 19:55:34 GMT
Server: Apache
Vary: Accept-Encoding
Content-Type: text/html; charset=iso-8859-1
# curl -I systemadmin.es/wp-content/plugins/noexisto_luego_existo/
HTTP/1.1 404 Not Found
Date: Mon, 04 Jul 2011 19:55:36 GMT
Server: Apache
Vary: Accept-Encoding
Content-Type: text/html; charset=iso-8859-1
Lo que evita que para esta configuración sean detectados los plugins. Pero si modificamos el plugin de nmap para que no incluya la barra final si que los podremos detectar con el mismo diccionario:
local target
if wp_root then
-- Give user-supplied argument the priority
target = wp_root .. "/wp-content/plugins/" .. line
elseif wp_autoroot then
-- Maybe the script has discovered another WordPress content directory
target = wp_autoroot .. "wp-content/plugins/" .. line
else
-- Default WP directory is root
target = "/wp-content/plugins/" .. line
end
Con esta modificación podremos ver como sí que encuentra los plugins instalados dentro del directorio plugins (que no significa que esten habilitados):
$ nmap -p80 --script=http-wp-plugins --script-arg 'http-wp-plugins.root="/",http-wp-plugins.search=all' systemadmin.es
Starting Nmap 5.59BETA1 ( http://nmap.org ) at 2011-07-04 19:41 CEST
Nmap scan report for systemadmin.es (87.98.227.154)
Host is up (0.044s latency).
rDNS record for 87.98.227.154: jordi.prats.systemadmin.es
PORT STATE SERVICE
80/tcp open http
| http-wp-plugins:
| search amongst the 14170 most popular plugins
(...)
| akismet
(...)
Nmap done: 1 IP address (1 host up) scanned in 62.73 seconds
Esta característica que hace detectables los plugins la podemos deshabilitar mediante la opción DirectorySlash. Por lo que podemos añadirla exclusivamente para el directorio de plugins con:
<Directory /var/www/systemadmin.es/htdocs/wp-content/plugins>
DirectorySlash Off
</Directory>
Una vez aplicados los cambios en el Apache podremos comprobar como el redirect ha desaparecido, comportándose igual con un directorio que existe:
# curl -I systemadmin.es/wp-content/plugins/akismet
HTTP/1.1 404 Not Found
Date: Mon, 04 Jul 2011 19:59:46 GMT
Server: Apache
Vary: Accept-Encoding
Content-Type: text/html; charset=iso-8859-1
# curl -I systemadmin.es/wp-content/plugins/akismet/
HTTP/1.1 404 Not Found
Date: Mon, 04 Jul 2011 19:59:49 GMT
Server: Apache
Vary: Accept-Encoding
Content-Type: text/html; charset=iso-8859-1
Que con uno que no existe:
# curl -I systemadmin.es/wp-content/plugins/noexisto_luego_existo
HTTP/1.1 404 Not Found
Date: Mon, 04 Jul 2011 19:59:53 GMT
Server: Apache
Vary: Accept-Encoding
Content-Type: text/html; charset=iso-8859-1
# curl -I systemadmin.es/wp-content/plugins/noexisto_luego_existo/
HTTP/1.1 404 Not Found
Date: Mon, 04 Jul 2011 19:59:54 GMT
Server: Apache
Vary: Accept-Encoding
Content-Type: text/html; charset=iso-8859-1
Por lo que dicho script ya no detecta que plugins de WordPress están instalados:
$ nmap -p80 --script=http-wp-plugins --script-arg 'http-wp-plugins.root="/",http-wp-plugins.search=all' systemadmin.es
Starting Nmap 5.59BETA1 ( http://nmap.org ) at 2011-07-04 20:03 CEST
Nmap scan report for systemadmin.es (87.98.227.154)
Host is up (0.038s latency).
rDNS record for 87.98.227.154: jordi.prats.systemadmin.es
PORT STATE SERVICE
80/tcp open http
|_http-wp-plugins: nothing found amongst the 14170 most popular plugins, use --script-arg http-wp-plugins.search=<number|all> for deeper analysis)
Nmap done: 1 IP address (1 host up) scanned in 62.83 seconds
Evidentemente, si el diccionario se modificara para buscar ficheros que deben estar presentes en el caso que el plugin este instalado (ficheros de estilo, imagenes...) esto no serviría de nada.
Gracias a estas modificaciones en la configuración del VirtualHost de Apache complicaremos un poco más la identificación y explotación de vulnerabilidades, con la esperanza que se busquen un objetivo más fácil.
Fuente:
http://systemadmin.es/2011/07/configuracion-segura-de-apache-para-wordpress