Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
zotlit-PoC — PoC — a importação de anexos copia arquivos de caminhos locais não aprovados no ZotLit (GHSA-4qh7-66xv-h329, CVE-2026-87000, CVSS 5.5). | Kitploit
Ferramentas/GitHubGitHub/squeeze440/zotlit-poc
Análise de VulnerabilidadesExploraçãoExfiltração de DadosColeta de InformaçõesVirtualização para SegurançaPapers e Pesquisa
GitHubsqueeze440/zotlit-poc

zotlit-PoC

PoC — a importação de anexos copia arquivos de caminhos locais não aprovados no ZotLit (GHSA-4qh7-66xv-h329, CVE-2026-87000, CVSS 5.5).

Ver Repositório
há 7 diasAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

ZotLit: aviso de segurança

Status da CVE: solicitada, aguardando atribuição. Esta descoberta é publicada como GHSA-4qh7-66xv-h329. Após a atribuição da CVE, este repositório é renomeado CVE-YYYY-NNNNN-zotlit-PoC e este banner é substituído pelo link da CVE.

PesquisadorDostxodjayev Abdullox (@squeeze440)
AvisoGHSA-4qh7-66xv-h329
CVSS 3.15.5 (Médio)
FraquezaCWE-73, CWE-200

Resumo

O Controle Externo de Nome de Arquivo ou Caminho no recurso de importação de anexos do AidenLx ZotLit (aidenlx/zotlit) 1.1.12 permite que um atacante que controla uma biblioteca Zotero compartilhada/sincronizada divulgue arquivos locais arbitrários do sistema de arquivos da vítima para o cofre Obsidian da vítima por meio de um caminho de anexo linked_file manipulado.

Produto

ZotLit — plugin do Obsidian para integração com o Zotero (aidenlx/zotlit, id do plugin zotlit, versão do manifesto 1.1.12)

Versão Testada

Commit do Git 41e60aaa6178629b34f8a42d104e757594b72435 (2026-07-31)

CVSS v3.1 Estimado

CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N — 5.5 (Médio)

Métricas não óbvias: AV:L — a exploração ocorre quando o processo local do Obsidian/zotlit da vítima processa metadados de itens do Zotero fornecidos pelo atacante (entregues por meio de uma biblioteca compartilhada/sincronizada), a mesma convenção usada para bugs de "arquivo malicioso processado por aplicativo local", embora a entrega em si possa ocorrer pela rede (biblioteca de grupo compartilhada, arquivo de exportação enviado por e-mail). UI:R — a vítima deve importar/sincronizar a biblioteca maliciosa no Zotero e executar o recurso de importação de notas do ZotLit (ou de incorporação de anotações/citações) em uma nota que faça referência ao anexo manipulado; isso é uso rotineiro da funcionalidade central do plugin, habilitada por padrão (attachment.import tem valor padrão true), não uma ação incomum. I:N/A:N — esta descoberta é apenas uma primitiva de leitura/cópia; nenhum path traversal no lado do destino é alegado (consulte Detalhes para uma observação relacionada, mas não verificada).

Detalhes

O ZotLit lê metadados de anexos diretamente do banco de dados SQLite do Zotero (ou de uma biblioteca sincronizada/compartilhada), incluindo a coluna de texto livre itemAttachments.path, e confia nela completamente ao resolver de onde ler um anexo "vinculado":

  • packages/db/src/lib/zt-path.ts:62-63 — attachmentAbsPath(), caso "linked-absolute":

    root@kitploit:~
    case "linked-absolute":
      return parsed.path;
    

    Para linhas com linkMode: 2 (linked_file) cujo path não carrega o placeholder de diretório base attachments:, parsed.path é a string bruta do banco de dados retornada literalmente como o caminho absoluto do sistema de arquivos a ser lido — sem allowlist, sem confinamento ao diretório de dados do Zotero ou a qualquer local aprovado pelo usuário.

  • packages/db/src/lib/context/zt-template-attach.ts:101-106 — attachmentFilename(), caso "linked-absolute":

    root@kitploit:~
    case "linked-absolute":
      return basename(path.path);
    

    O nome de arquivo usado para construir a cópia no cofre é derivado desse mesmo caminho controlado pelo atacante por meio de basename(), portanto o nome de arquivo de destino é influenciado pelo atacante, mas livre de separadores de caminho (seguro contra traversal neste ramo).

  • apps/obsidian/src/services/note-import/note-parser.ts:403-430 — resolveEmbeddedImage() é invocado durante a conversão de uma anotação de imagem incorporada de uma nota de literatura do Zotero em Markdown do Obsidian (uma ação rotineira e padrão do recurso "Import Note" do ZotLit). Ele resolve sourcePath = attachmentAbsPath(attachment, ...) e chama deps.resolveLink({ sourcePath, vaultName: \${attachment.key}-${filename}` })` — enfileirando uma cópia de qualquer caminho absoluto escolhido pelo atacante para dentro do cofre.

  • apps/obsidian/src/services/attachment-import/service.ts:125-155 — AttachmentImportBatch.resolveLink() enfileira { source: sourcePath, dest: <vault attachment folder>/<key>-<filename> }, condicionado apenas à configuração attachment.import, cujo padrão é true (apps/obsidian/src/services/settings/schema.ts:123).

  • apps/obsidian/src/lib/copy-attachments.ts:43-60 — copyAttachment() executa a leitura+escrita real sem nenhuma validação de caminho: stat(source) e depois copyFile(source, dest).

Efeito líquido: um atacante que consiga inserir um item do Zotero linked_file (linkMode 2) na biblioteca da vítima — por exemplo, uma biblioteca de grupo compartilhada do Zotero, uma exportação .rdf/.json/Better BibTeX que a vítima importa, ou uma biblioteca sincronizada na qual o atacante tem acesso de escrita — pode definir o caminho de anexo desse item para qualquer arquivo no disco da vítima (~/.ssh/id_rsa, armazenamentos de credenciais do navegador, outros cofres, arquivos .env, etc.). No momento em que a vítima executa a importação de notas do ZotLit (ou renderiza/incorpora essa anotação) com a configuração padrão attachment.import: true, o ZotLit copia silenciosamente o conteúdo desse arquivo para o cofre Obsidian da vítima sob um nome previsível (<attachmentKey>-<basename>). Como os cofres são rotineiramente sincronizados, commitados no git ou publicados, isso move dados que o atacante jamais conseguiria alcançar de outra forma para um local que o atacante (ou qualquer outra pessoa com acesso ao destino de sincronização) pode ler.

Observação relacionada, não verificada (não faz parte do PoC desta descoberta): o ramo irmão "storage" de attachmentFilename() (zt-template-attach.ts:103-104) retorna o sufixo bruto do caminho sem a chamada basename() aplicada aos outros dois ramos. Se isso é explorável de forma independente depende de como o próprio mecanismo de sincronização de armazenamento do Zotero nomeia os arquivos baixados localmente, o que está fora deste repositório e não foi verificado — sinalizado aqui apenas como uma lacuna de hardening que vale a pena fechar por consistência.

Prova de Conceito

Verificação dinâmica: as funções vulneráveis exatas (parseAttachmentPath, attachmentAbsPath, attachmentFilename, copyAttachments/copyAttachment/writeCopy/destMatches, isErrno, reflink) foram extraídas literalmente (com arquivo:linha citados acima, lógica inalterada) do código-fonte distribuído e executadas diretamente no Node, porque uma instalação completa offline do workspace pnpm não estava disponível neste sandbox (toolchain corepack/pnpm quebrado offline). A única substituição foi trocar a chamada do logger LogTape por console.warn — apenas cosmético, efeito zero no fluxo de controle. Script: ~/engagements/zotlit/evidence/poc-verify.mjs.

Passos:

  1. Segredo simulado da vítima em ~/engagements/zotlit/evidence/victim-disk/id_rsa (conteúdo fictício, claramente marcado como simulado).
  2. Linha de anexo do Zotero controlada pelo atacante e manipulada: { key: "EVILKEY1", path: "<path to victim's id_rsa>", linkMode: 2 } — exatamente o formato que getAttachmentByKey retorna do banco de dados do Zotero.
  3. Executou a attachmentAbsPath() real — resolveu a origem como o arquivo da vítima, literalmente, sem validação.
  4. Executou a attachmentFilename() real — resolveu id_rsa como o basename de destino aparentemente seguro.
  5. Reproduziu a construção real do vaultName a partir de note-parser.ts:427 (${key}-${filename}).
  6. Executou a copyAttachments() real — resultado { copied: 1, skipped: 0, missing: 0 }.
  7. Leu de volta fake-vault/attachments/EVILKEY1-id_rsa — conteúdo byte a byte idêntico ao arquivo original da vítima.

Captura de tela da execução completa (comando + saída) em um xterm real: ../evidence/poc-run.png

Impacto

Um atacante que consiga influenciar o conteúdo da biblioteca Zotero de uma vítima (biblioteca compartilhada/de grupo, exportação de bibliografia importada ou biblioteca sincronizada) pode exfiltrar arquivos locais arbitrários que o usuário do SO da vítima consegue ler — chaves SSH, armazenamentos de credenciais, conteúdos de outros cofres, segredos em .env/configurações — para o cofre Obsidian da vítima, sem nenhum prompt ou confirmação, no momento em que a vítima usa a funcionalidade central de importação de notas do ZotLit com as configurações padrão. Os cofres são comumente sincronizados (Obsidian Sync, git, pastas na nuvem) ou publicados, então isso converte uma primitiva de leitura de arquivo local em exposição remota realista.

Fraquezas

  • CWE-73: Controle Externo de Nome de Arquivo ou Caminho
  • CWE-200: Exposição de Informação Sensível a um Ator Não Autorizado

Remediação

Sugere-se confinar as origens de anexos linked_file (linkMode 2) a locais do sistema de arquivos que a vítima configurou ou aprovou explicitamente (por exemplo, o próprio baseAttachmentPath configurado do Zotero, ou o diretório de dados do Zotero), e solicitar confirmação ao usuário antes de copiar automaticamente um anexo vinculado cujo caminho esteja fora de qualquer raiz esperada. Como defesa em profundidade, considere aplicar a mesma sanitização apenas com basename() já usada nos ramos linked-absolute/linked-base de attachmentFilename() também ao ramo "storage", para que nenhum caminho de código retorne um fragmento de nome de arquivo não sanitizado.

Crédito

Dostxodjayev Abdullox (GitHub: squeeze440)

Canal de Relato

O relato privado de vulnerabilidades está habilitado em aidenlx/zotlit — relate por meio de um rascunho de Aviso de Segurança do GitHub (GHSA) no repositório, em vez de uma issue pública.

Baixar ferramenta