CVE-2026-41651 — PackageKit TOCTOU Escalação Local de Privilégios
Classificação: Artefato de Avaliação Purple Team
Uso autorizado apenas. Este documento e o script de teste que o acompanha destinam-se exclusivamente à validação interna de segurança em sistemas onde foi obtida autorização por escrito.
Prova de Exploração

Índice
- Visão Geral da Vulnerabilidade
- Análise Técnica
- Descrição do Script de Teste
- Indicadores de Comprometimento
- Lógica de Detecção
- Sistemas e Versões Afetados
- Remediação
- Referências
Visão Geral da Vulnerabilidade
PackageKit é uma camada de abstração D-Bus para gerenciamento de pacotes do sistema, presente por padrão em desktops baseados em GNOME em Debian, Ubuntu, Fedora, RHEL, SUSE e Arch Linux. Como ele media operações privilegiadas de pacotes em nome de usuários sem privilégios, uma falha em seu fluxo de autorização tem impacto de root em todo o sistema.
Análise Técnica
Causa Raiz
pk-transaction.c (pré-1.3.5) não aplicava uma proteção de estado na re-invocação de métodos de ação. Um cliente D-Bus poderia chamar InstallFiles (ou outros métodos de ação) múltiplas vezes no mesmo objeto de transação depois que ele já tivesse saído de PK_TRANSACTION_STATE_NEW.
Cadeia de Ataque
Atacante (sem privilégios)
│
├─① CreateTransaction() → PackageKit retorna o caminho do objeto da transação (tid)
│
├─② InstallFiles(tid, FLAG_SIMULATE=4, [dummy.pkg])
│ PackageKit enfileira uma verificação de autorização polkit para dummy.pkg.
│ Nenhuma instalação ocorre ainda — SIMULATE significa apenas teste simulado.
│
├─③ InstallFiles(tid, FLAG_NONE=0, [payload.pkg]) ← janela TOCTOU
│ Re-invoca no mesmo tid antes que a autorização seja resolvida.
│ Versões vulneráveis sobrescrevem os parâmetros enfileirados com payload.pkg.
│
└─④ polkit concede autorização (usuário aprovou ou autorização automática)
packagekitd instala payload.pkg como root.
script postinst/post do payload: install -m 4755 /bin/bash /tmp/.suid_bash
Atacante executa /tmp/.suid_bash -p → shell root.
Por Que a Corrida Vence
Os passos ② e ③ são enviados como chamadas D-Bus assíncronas não bloqueantes na mesma conexão e liberados em uma única escrita. As duas mensagens chegam ao packagekitd antes que ele possa processar ② e avançar a máquina de estados, deixando a janela TOCTOU aberta. A correção em 1.3.5 adiciona uma verificação explícita de estado que retorna PK_TRANSACTION_ERROR_INVALID_STATE em qualquer re-invocação após PK_TRANSACTION_STATE_NEW.
Descrição do Script de Teste
Arquivo: cve-2026-41651-purpleteam.py
Linguagem: Python 3
Dependências: python3-gi (introspecção GObject / bindings GLib/Gio)
Propósito
Demonstra a explorabilidade do CVE-2026-41651 em um sistema de teste preparado para os seguintes fins:
- Validar se a versão instalada do PackageKit é vulnerável
- Gerar telemetria IOC realista para ajuste de SIEM/EDR
- Testar a cobertura de detecção antes e depois da aplicação do patch
Comportamento
Suporte a Ambientes Reforçados
Sistemas reforçados por padrão podem bloquear a exploração em dois pontos independentes. O script lida com ambos automaticamente.
1. umask restritivo (027 / 077)
Um umask herdado pelo processo de 027 ou 077 faz com que mkdir() produza diretórios 750 ou 700. Tanto dpkg-deb quanto rpmbuild precisam percorrer toda a árvore de build — se qualquer diretório for ilegível, o build falha silenciosamente.
Correção aplicada: os.umask(0o022) é chamado na inicialização antes de qualquer arquivo ou diretório ser criado. Além disso, todo diretório e arquivo na árvore de build recebe um chmod explícito imediatamente após a criação (0o755 para diretórios e scripts, 0o644 para arquivos de dados), garantindo as permissões corretas independentemente do umask herdado.
2. Flags de montagem nosuid / noexec em /tmp
| Flag | Efeito na exploração |
|---|
nosuid | O kernel remove silenciosamente o bit SUID de qualquer arquivo armazenado nesse sistema de arquivos — o bash copiado nunca se torna root |
noexec | O binário SUID não pode ser executado de forma alguma |
Correção aplicada: Na inicialização, _find_suid_dir() lê /proc/mounts e testa diretórios candidatos em ordem de preferência até encontrar um cujo sistema de arquivos não tenha nenhuma das flags definidas. O caminho resolvido é então incorporado ao script pós-instalação do payload e usado para verificação e execução.
Se todos os candidatos estiverem bloqueados, o script sai com um erro claro em vez de falhar silenciosamente.
Compatibilidade
| Família de Distribuição | Ferramenta de Pacote | Testado |
|---|
| Debian / Ubuntu | dpkg-deb | ✓ |
|
Indicadores de Comprometimento
Os IOCs são listados do nível genérico/de infraestrutura até artefatos específicos do script. Detecções baseadas nos indicadores genéricos capturarão este CVE independentemente de qual variante de PoC for usada.
Sistema de Arquivos
Processo e Execução
Atividade D-Bus
Padrões de Log de Auditoria
Habilite com: auditctl -a always,exit -F arch=b64 -S all -F path=/usr/bin/packagekitd
Ou use as regras abaixo em /etc/audit/rules.d/:
# Detecta criação de arquivo SUID em todos os diretórios de descarte candidatos
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F a2&04000 -F dir=/tmp -k suid_drop
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F a2&04000 -F dir=/var/tmp -k suid_drop
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F a2&04000 -F dir=/dev/shm -k suid_drop
# Detecta dpkg-deb / rpmbuild por não-root
-w /usr/bin/dpkg-deb -p x -k pkg_build_nonroot
-w /usr/bin/rpmbuild -p x -k pkg_build_nonroot
# Detecta execução de bash SUID a partir de qualquer diretório de descarte candidato
-a always,exit -F arch=b64 -S execve -F dir=/tmp -F uid!=0 -F euid=0 -k priv_esc_drop
-a always,exit -F arch=b64 -S execve -F dir=/var/tmp -F uid!=0 -F euid=0 -k priv_esc_drop
-a always,exit -F arch=b64 -S execve -F dir=/dev/shm -F uid!=0 -F euid=0 -k priv_esc_drop
Artefatos do Gerenciador de Pacotes
Artefatos de Escalação de Privilégios
Lógica de Detecção
Pseudo-Regra SIEM (Genérica — cobre todas as variantes do CVE-2026-41651)
(
event.category == "process"
AND process.name IN ("dpkg-deb", "rpmbuild")
AND process.user.id != "0"
AND NOT process.parent.name IN ("apt", "apt-get", "dpkg", "rpm", "dnf", "yum", "zypper", "mock", "koji")
)
OR
(
event.category == "file"
AND file.path LIKE "/tmp/%" OR file.path LIKE "/var/tmp/%" OR file.path LIKE "/dev/shm/%"
AND file.owner == "root"
AND (file.mode LIKE "04%")
)
OR
(
event.category == "process"
AND process.name == "bash"
AND process.real_user.id != "0"
AND process.effective_user.id == "0"
AND NOT process.parent.name IN ("sudo", "su", "sshd", "login", "pam")
)
Cadeia Comportamental EDR
packagekitd
└─ sh / bash (cwd ou argumento corresponde a /tmp, /var/tmp, /dev/shm ou $HOME)
└─ install / cp / chmod (destino tem SUID + proprietário root)
Sinalize a cadeia completa. Qualquer etapa individual sozinha pode ser benigna; a relação pai-filho através de packagekitd até um comando que define SUID é de alta fidelidade, independentemente de qual diretório de descarte foi selecionado. Amplie regras baseadas em caminho para cobrir todos os quatro candidatos.
Sistemas e Versões Afetados
Verifique a versão instalada: pkcon backend-details ou packagekit --version
Vulnerável se a versão relatada for ≤ 1.3.4.
Principal: Atualize o PackageKit para 1.3.5 ou aplique o backport específico do fornecedor.
# Debian / Ubuntu
apt update && apt install --only-upgrade packagekit
# Fedora / RHEL
dnf upgrade packagekit
# SUSE
zypper update packagekit
Mitigações (se a aplicação do patch não for imediatamente possível):
Referências
Gerado: 2026-04-24 | Atualizado: 2026-04-25 | Avaliação Purple Team | Uso Interno Apenas