WordPress é um sistema livre e aberto de gestão de conteúdo para a internet, baseado em PHP com banco de dados MySQL, executado em um servidor interpretador, voltado principalmente para a criação de páginas eletrônicas e blogs online.
Estrutura padrão do WordPress
tree -L 1 /var/www/html
├── index.php
├── license.txt
├── readme.html
├── wp-activate.php
├── wp-admin
├── wp-blog-header.php
├── wp-comments-post.php
├── wp-config.php
├── wp-config-sample.php
├── wp-content
├── wp-cron.php
├── wp-includes
├── wp-links-opml.php
├── wp-load.php
├── wp-login.php
├── wp-mail.php
├── wp-settings.php
├── wp-signup.php
├── wp-trackback.php
└── xmlrpc.php
Arquivos chaves do WordPress
O diretório pai do WordPress possui arquivos que são necessários para o WordPress funcionar corretamente.
index.php
é a página padrão WordPresslicense.txt
contém informações úteis tais como a versão do WordPress instalado.wp-activate.php
é utilizado para a configuração inicial do e-mail durante a instalação do WordPress.wp-admin
é um diretório que contém a página do administrador para o dashboard do backend. Uma vez que o usuário estiver logado, ele pode fazer modificações baseadas em suas permissões. A página de login pode ser localizada em dos seguintes diretórios:/wp-admin/login.php
/wp-admin/wp-login.php
/login.php
/wp-login.php
Esse arquivo também pode ser renomeado para fazer mais difícil de encontrar a página final.
xmlrpc.php
é um arquivo que representa uma feature do WordPress que permite que informação seja enviada através do HTTP agindo como um mecanismo de transporte e o XML agindo como mecanismo de codificação. Essa feature foi substituída pelo WordPress REST API.wp-config.php
é um arquivo que contém informações que o WordPress utiliza para conectar com o banco de dados, como nomes de tabelas, hosts de banco de dados, usuário e senha, chaves de autenticação e salts, e o prefixo da tabela. Esse arquivo de configuração também pode ser utilizado para ativar o modo de DEBUG, que pode ser útil para arrumar problemas.
<?php
/** <SNIP> */
/** The name of the database for WordPress */
define( 'DB_NAME', 'database_name_here' );
/** MySQL database username */
define( 'DB_USER', 'username_here' );
/** MySQL database password */
define( 'DB_PASSWORD', 'password_here' );
/** MySQL hostname */
define( 'DB_HOST', 'localhost' );
/** Authentication Unique Keys and Salts */
/* <SNIP> */
define( 'AUTH_KEY', 'put your unique phrase here' );
define( 'SECURE_AUTH_KEY', 'put your unique phrase here' );
define( 'LOGGED_IN_KEY', 'put your unique phrase here' );
define( 'NONCE_KEY', 'put your unique phrase here' );
define( 'AUTH_SALT', 'put your unique phrase here' );
define( 'SECURE_AUTH_SALT', 'put your unique phrase here' );
define( 'LOGGED_IN_SALT', 'put your unique phrase here' );
define( 'NONCE_SALT', 'put your unique phrase here' );
/** WordPress Database Table prefix */
$table_prefix = 'wp_';
/** For developers: WordPress debugging mode. */
/** <SNIP> */
define( 'WP_DEBUG', false );
/** Absolute path to the WordPress directory. */
if ( ! defined( 'ABSPATH' ) ) {
define( 'ABSPATH', __DIR__ . '/' );
}
/** Sets up WordPress vars and included files. */
require_once ABSPATH . 'wp-settings.php';
Diretórios chaves do WordPress
- O diretório
wp-content
é o diretório principal onde plugins e temas são armazenados. O subdiretóriouploads/
é normalmente onde qualquer arquivo upado para a plataforma é armazenado. Esses diretórios devem ser cuidadosamente enumerados pois podem conter informação sensível que ode levar a um Remote Code Execution ou outras maneiras de exploitar o sistema por falta de configuração.
tree -L 1 /var/www/html/wp-content
├── index.php
├── plugins
└── themes
- O
wp-includes
contém tudo além de componentes administrativos e temas que pertencem ao site. Esse diretório é onde os principais arquivos estão armazenados, como certificados, fontes, arquivos de JavaScript, e widgets.
tree -L 1 /var/www/html/wp-includes
├── <SNIP>
├── theme.php
├── update.php
├── user.php
├── vars.php
├── version.php
├── widgets
├── widgets.php
├── wlwmanifest.xml
├── wp-db.php
└── wp-diff.php
Cargos
Existem 5 tipos de cargos para um WordPress padrão.
Cargo | Descrição |
---|---|
Administrador/administrator | Esse usuário tem acesso administrativo dentro de todas as dependências do site. Isso incluí adicionar ou remover usuários, posts, como também modificar o código fonte. |
Editor/editor | Um editor pode publicar e modificar os posts, incluindo posts de outros usuários. |
Autor/author | Autores podem adicionar e modificar seus próprios posts. |
Contribuidor/contributor | Esses usuários podem escrever e administrar suas próprias publicações, mas não podem publicá-las. |
Inscrito/subscriber | Esses são usuários normais que podem navegar pelas publicações e modificar seus perfis. |
Ganhar acesso ao administrador significa ter acesso a um possível [[(CWE-94) Improper Control of Generation of Code (‘Code Injection’) | Remote Code Execution]]. Contudo, editores e autores podem ter acesso a certas vulnerabilidades de plugins que outros usuários não possuem. |
Enumeração
Enumeração da versão do WordPress
É sempre importante saber a versão da aplicação que nós estamos trabalhando. Uma parte essencial da enumeração é descobrir a versão do software que estamos lidando e seu número de versão. Isso nos ajuda quando estamos procurando por má configurações, tais como senhas padrões que podem estar definidas em algumas versões da aplicação e pesquisar por vulnerabilidades conhecidas em versões específicas. Nós podemos utilizar uma variedade de métodos para descobrir a versão manualmente. A primeira e mais simples delas é verificar o código fonte da página. Nós podemos clicar com o botão direito em qualquer ponto da página e clicar em “View page source”, ou usar o atalho do teclado CTRL + U.
Enumeração de plugins e temas
Nós também podemos encontrar informações a respeito de plugins e temas instalados através de uma revisão do código fonte. Nós podemos usar o seguinte comando no cURL para isso:
curl -s -X GET http://www.site.com | sed 's/href=/\n/g' | sed 's/src=/\n/g' | grep 'wp-content/plugins/*' | cut -d"'" -f2
curl -s -X GET http://blog.inlanefreight.com | sed 's/href=/\n/g' | sed 's/src=/\n/g' | grep 'themes' | cut -d"'" -f2
Enumeração de plugins ativos
Se nós fizermos uma requisição ao plugin em especifico e recebermos um 301 Moved Permanently
, então sabemos que o plugins está ativo. Caso contrário, se responder com um 404 Not Found
, sabemos que o plugin não existe.
curl -I -X GET http://blog.inlanefreight.com/wp-content/plugins/mail-masta
HTTP/1.1 301 Moved Permanently
Date: Wed, 13 May 2020 20:08:23 GMT
Server: Apache/2.4.29 (Ubuntu)
Content-Length: 356
Content-Type: text/html; charset=iso-8859-1
curl -I -X GET http://blog.inlanefreight.com/wp-content/plugins/someplugin
HTTP/1.1 404 Not Found
Date: Wed, 13 May 2020 20:08:18 GMT
Server: Apache/2.4.29 (Ubuntu)
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Cache-Control: no-cache, must-revalidate, max-age=0
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
O mesmo se aplica a temas.
Para acelerar a enumeração, podemos usar ferramentas como o WPScan ou o wfuzz.
Enumeração de usuários
Enumerar usuários é uma parte crítica do WordPress. Com isso, talvez nós sejamos capazes de adivinhar a senha padrão de usuários através de credenciais padrões ou realizar ataques de força bruta. Se conseguirmos, nós talvez sejamos capazes de logar no sistema como autor ou até mesmo administrador. Esse acesso pode levar a modificar o WordPress ou até mesmo interagir com o servidor. Existem duas maneiras de fazer isso:
Primeiro método
O primeiro método é verificar o autor dos posts para tentar descobrir o ID de usuários correspondentes ao seu nome de usuário. Se nós colocarmos o mouse por cima do nome do autor, um link para o nome do usuário aparecerá no canto esquerdo inferior do navegador.
Outra coisa que podemos fazer é verificar o ID do usuário. Podemos fazer isso através do cURL. Isso pode ser feito seguindo o exemplo:
curl -s -I -X GET http://blog.inlanefreight.com/?author=1
HTTP/1.1 301 Moved Permanently
Date: Wed, 13 May 2020 20:47:08 GMT
Server: Apache/2.4.29 (Ubuntu)
X-Redirect-By: WordPress
Content-Length: 0
Content-Type: text/html; charset=UTF-8
Recebemos um 301 Moved Permanently
caso o usuário com esse ID exista. Caso contrário, recebemos um 404 Not Found
Segundo método
A segunda maneira requer interagir com um endpoint de requisição JSON, que nos permite obter a lista de usuários. Isso foi mudado no WordPress 4.7.1, e versões depois dessa.
curl http://blog.inlanefreight.com/wp-json/wp/v2/users | jq
[
{
"id": 1,
"name": "admin",
"url": "",
"description": "",
"link": "http://blog.inlanefreight.com/index.php/author/admin/",
<SNIP>
},
{
"id": 2,
"name": "ch4p",
"url": "",
"description": "",
"link": "http://blog.inlanefreight.com/index.php/author/ch4p/",
<SNIP>
},
<SNIP>
Login
Uma vez que temos em mãos usuários validos, nós podemos tentar montar um script de força bruta para tentar ganhar acesso ao backend do WordPress. Esse ataque pode ser feito através do xmlrpc.php
.
Se nós realizarmos uma requisição POST em xmlrpc.php
com credenciais validas, nós receberemos o seguinte output:
curl -X POST -d "<methodCall><methodName>wp.getUsersBlogs</methodName><params><param><value>admin</value></param><param><value>CORRECT-PASSWORD</value></param></params></methodCall>" http://blog.inlanefreight.com/xmlrpc.php
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<params>
<param>
<value>
<array><data>
<value><struct>
<member><name>isAdmin</name><value><boolean>1</boolean></value></member>
<member><name>url</name><value><string>http://blog.inlanefreight.com/</string></value></member>
<member><name>blogid</name><value><string>1</string></value></member>
<member><name>blogName</name><value><string>Inlanefreight</string></value></member>
<member><name>xmlrpc</name><value><string>http://blog.inlanefreight.com/xmlrpc.php</string></value></member>
</struct></value>
</data></array>
</value>
</param>
</params>
</methodResponse>
Se as credencias não forem validas, receberemos um 403 faultCode
.