Configuración segura de Apache para WordPress

Iniciado por el-brujo, 12 Julio 2011, 19:51 PM

0 Miembros y 1 Visitante están viendo este tema.

el-brujo

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