Meu cliente foi hackeado por um plugin 'nulled'. O que todo plugin WordPress precisa ter
nonce, capability, sanitize, escape. as 4 coisas que eu olho antes de instalar qualquer plugin
Contents
oxente, que semana. cliente meu aqui em salvador, uma pousada, comprou um plugin "premium" de reservas num site desses de plugin pirata. de graça. massa né? três semanas depois o google search console mandou alerta e o site tava cheio de página de cassino em russo e japonês. barril.
como eu achei
primeira coisa, ver quem é admin:
wp user list --role=administrator
tinha um usuário "wp_support" que ninguém criou. clássico. depois:
wp core verify-checksums
wp plugin verify-checksums --all
grep -rn "base64_decode\|eval(" wp-content/plugins wp-content/uploads
o verify-checksums do core compara os arquivos com os oficiais do wordpress.org. o dos plugins só funciona pra plugin que existe no repositório oficial, o pirata não tem checksum, óbvio. e o grep achou um eval(base64_decode(...)) enterrado num arquivo chamado class-license-check.php. "license check" kkkk a ironia.
limpeza: removi o plugin, apaguei o usuário, troquei TODAS as senhas e os salts do wp-config.php, reinstalei o core, procurei .php dentro de uploads (não pode ter nenhum), e pedi reindexação pro google. dois dias de trabalho. cobrei, claro.
o que um plugin decente faz (e o seu precisa fazer)
como eu acabei reescrevendo a parte de reservas do zero, aqui o esqueleto que eu uso. quatro regras:
// no formulário
wp_nonce_field('mb_salvar_reserva');
// no handler
add_action('admin_post_mb_salvar_reserva', 'mb_salvar_reserva');
function mb_salvar_reserva() {
// 1. permissão primeiro
if (! current_user_can('edit_posts')) {
wp_die('sem permissão', 403);
}
// 2. nonce (protege contra CSRF, NÃO é permissão)
check_admin_referer('mb_salvar_reserva');
// 3. sanitize na entrada
$nome = sanitize_text_field(wp_unslash($_POST['nome'] ?? ''));
$email = sanitize_email(wp_unslash($_POST['email'] ?? ''));
$noites = absint($_POST['noites'] ?? 0);
// SQL sempre com prepare
global $wpdb;
$wpdb->query($wpdb->prepare(
"INSERT INTO {$wpdb->prefix}mb_reservas (nome, email, noites) VALUES (%s, %s, %d)",
$nome,
$email,
$noites
));
wp_safe_redirect(admin_url('admin.php?page=mb-reservas&ok=1'));
exit;
}
// 4. escape na saída, sempre, mesmo que "venha do banco"
echo '<td>' . esc_html($reserva->nome) . '</td>';
echo '<a href="' . esc_url($link) . '">' . esc_html__('Ver', 'mb') . '</a>';
- capability: quem pode fazer isso?
current_user_canantes de tudo. - nonce: o pedido veio mesmo do seu formulário?
check_admin_referer. - sanitize: limpa o que entra.
sanitize_text_field,absint,sanitize_email. - escape: limpa o que sai.
esc_html,esc_attr,esc_url.
e se tiver endpoint REST, o permission_callback é obrigatório. nada de __return_true em rota que grava coisa.
resumo da ópera: plugin pirata é backdoor com frete grátis. o cliente economizou 59 dólares e pagou 400 pra mim limpar. PHP paga meu aluguel, mas eu preferia que fosse por outro motivo kkkk 🌴
Written by
Matheus Barreto
freela de wordpress e php desde 2016, salvador bahia 🌴 cliente que pede "só um sitezinho" agora eu cobro em dólar kkkk
Get the best of #php_still_pays weekly
One email each Monday with the most useful posts. No spam; unsubscribe in one click.
Comments
Sign in to join the conversation.
Sign in to comment