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
tiandy-research — Este repositório contém os resultados da minha pesquisa de agosto de 2020 sobre o firmware de IPC/NVR da Tiandy. Encontrei duas vulnerabilidades que poderiam ser usadas para recuperar remotamente a senha do administrador e obter acesso root ao dispositivo. | Kitploit
Ferramentas/GitHubGitHub/zb3/tiandy-research
Segurança de Sistemas EmbarcadosQuebra de SenhasEscalada de PrivilégiosAnálise de VulnerabilidadesExploraçãoTestes de PenetraçãoAutenticaçãoPapers e PesquisaRed TeamingAnálise de Firmware
GitHubzb3/tiandy-research
302há 5 anosRevisado pelo Kitploit

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

tiandy-research

Este repositório contém os resultados da minha pesquisa de agosto de 2020 sobre o firmware de IPC/NVR da Tiandy. Encontrei duas vulnerabilidades que poderiam ser usadas para recuperar remotamente a senha do administrador e obter acesso root ao dispositivo.

Ver Repositório

tiandy-research

Este repositório contém os resultados da minha pesquisa de agosto de 2020 sobre o firmware IPC/NVR da Tiandy (esses dispositivos também são vendidos como OMNY). Esta "pesquisa" não foi exaustiva, mas encontrei vários métodos para recuperar remotamente a senha do administrador, ativar o telnet e alterar a senha do root.

É difícil dizer exatamente quais versões são afetadas, já que só podemos baixar as recentes. Todas estas versões para download são afetadas:

root@kitploit:~
DVRS_V9.12.7.20200422
DVRS_V11.7.4.20200721
NVSS_V13.6.1.20200723
NVSS_V22.1.0.20200722

Não só existem diferentes ramos para diferentes dispositivos, mas alguns componentes são versionados e atualizados separadamente, como a API web, onde encontrei um bypass de autenticação que só funciona em versões lançadas desde meados de 2019, independentemente do número da versão do firmware. Se por acaso você souber mais sobre as versões afetadas, agradeço sua ajuda.

Estou fazendo divulgação completa aqui, mas é razoável. Um patch do fornecedor (improvável, já que eles não respondem) não faria o problema desaparecer, especialmente quando nenhum dispositivo online tem o firmware mais recente (nem de longe). A vulnerabilidade real é que esses dispositivos estão expostos à internet. E isso é algo que os usuários finais precisam corrigir, não a Tiandy.

Como bônus, também estou incluindo o descompactador de firmware e algumas informações sobre como acessar os fluxos via RTSP/RTMP (boa sorte tentando encontrar isso no manual).

O que há aqui

Primeiramente apresento os scripts:

  • Recuperação de senha
  • Obtendo root

Em seguida, tento explicar brevemente o que esses scripts fazem e porquê. Não repito o código, mas tento explicar contexto suficiente para você entender o código:

  • Visão geral
  • As vulnerabilidades
  • Além da recuperação de senha

Por fim, a coisa fica relativamente técnica:

  • Descompactando o firmware
  • Encontrando dispositivos Tiandy na internet
  • Bônus: URLs RTSP e RTMP

Recuperação de senha

Você precisará de Python 3 com PyCrypto.

Primeiro, tente recover.py. Isso requer que a porta 3001 esteja acessível:

root@kitploit:~
python3 recover.py [HOST]

se tudo correr bem, as credenciais do administrador devem ser impressas.

Se essa porta não estiver acessível, a da web pode funcionar. Isso requer a url:

root@kitploit:~
python3 cgi_recover.py http://123.45.67.89
python3 cgi_recover.py https://123.45.67.89

Se nenhum dos métodos acima funcionar, verifique se o telnet está habilitado. Se estiver, você pode obter root no dispositivo diretamente, basta quebrar este hash:

root@kitploit:~
support:$1$$AErA9BQgLjrxTJB1748k71:501:501:Linux User,,,:/home/support:/bin/sh

(abra um PR caso consiga quebrá-lo :D)

Obtendo root

Firmware antigo

Em firmwares NVR V7 mais antigos, você pode executar comandos diretamente:

root@kitploit:~
python3 ftpupdate.py [host] [adminpass] '[cmd]'

mas não dá nenhuma saída. Para facilitar, incluí este atalho:

root@kitploit:~
python3 ftpupdate.py [host] [adminpass] adduser [username] [password]

Isso adicionará outro usuário com uid 0.

Firmware mais recente

Primeiro, habilite o telnet usando:

root@kitploit:~
python3 telnet.py [host] [adminpw]

ou para dispositivos recentes:

root@kitploit:~
python3 cgi_recover.py [host] telnet

Então você pode sobrescrever /etc/passwd (presumo que você saiba como isso funciona). Tente filetransport.py primeiro (para NVRs):

root@kitploit:~
python3 filetransport.py [host] [adminpass] put /etc/passwd <[source_file]

isso não dá nenhum retorno; você precisa testar tentando fazer login...

Para modelos IPC onde filetransport.py não funciona, tente upgrade_rw.py:

root@kitploit:~
python3 upgrade_rw.py [url] [adminpass] /etc/passwd <[source_file]

(isso também não dá nenhum retorno)

Por fim, para dispositivos ainda mais novos, isso também pode ser feito pela API web:

root@kitploit:~
python3 cgi_recover.py [url] write /etc/passwd <[source_file]

Se nenhum dos métodos acima funcionou (verifique se você consegue fazer login), tente novamente todos esses métodos, mas sobrescreva /config/etc/passwd em vez disso. Em algumas versões do firmware, /etc/passwd é um symlink para esse caminho. Por fim, você também pode tentar sobrescrever /tdfs/etc/passwd, mas depois disso pode ser necessário reiniciar o dispositivo; para reiniciar, use:

root@kitploit:~
python3 reboot.py [host] [adminpass]

Visão geral

O firmware antigo V7 (IPC e NVR) não parece ser afetado, mas se você tiver a senha do administrador, para NVRs existe um RCE autenticado (ftpupdate.py), e para IPCs, o script upgrade-rw.py pode ser usado para sobrescrever /etc/passwd.

Versões posteriores do firmware NVR (V9 e V11) têm uma conta padrão que, combinada com escalonamento de privilégios "passivo", torna possível recuperar a senha do administrador. Podemos então sobrescrever /etc/passwd usando filetransport.py.

Embora a conta padrão não esteja presente no firmware IPC, outro método de recuperação aparece: o método PSW. Este é um mecanismo de recuperação de senha sem segurança alguma. Está presente em todas as versões de firmware para download desde o V9. Enquanto filetransport.py só funciona em NVRs, upgrade_rw.py alcança o mesmo propósito em IPCs usando o mecanismo de atualização, para que ainda possamos obter o acesso root.

O firmware de 2019 introduz outro vetor de ataque: um bypass de autenticação usando a API web. Ao exportar o arquivo de configuração sem autenticação, podemos recuperar a senha e preparar um pacote de atualização para sobrescrever arquivos arbitrários.

Falando em vulnerabilidades, existem 4 delas:

  • Credenciais telnet fixas no código (firmware NVR antigo)
  • Escalonamento de privilégio autenticado (qualquer usuário pode ler a senha do administrador)
  • Recuperação de senha insegura (chave de criptografia simétrica embutida no binário)
  • Bypass de autenticação da API web (adicionar certas strings ao caminho da URL desativa a autenticação)

Observe que não investiguei os recursos "cloud", ou seja, se é possível enumerar dispositivos e, portanto, conectar-se a dispositivos não expostos à internet (como acontece com dispositivos Xiongmai).

As vulnerabilidades

Credenciais telnet fixas para firmware antigo

Em versões antigas, o telnet é habilitado por padrão e é isto que podemos encontrar no arquivo /etc/passwd:

root@kitploit:~
support:$1$$AErA9BQgLjrxTJB1748k71:501:501:Linux User,,,:/home/support:/bin/sh

(a senha do root é atualizada dinamicamente; também não quebrei este hash, então pull requests são mais que bem-vindos :D)

O usuário support (na verdade presente em todas as versões do firmware) pode parecer sem privilégios, mas, é claro, esse usuário tem privilégios suficientes para ler a senha do Admin e sobrescrever scripts de inicialização graváveis por todos em /etc/init.d ou até mesmo criar novos :)

A conta padrão + escalonamento de privilégio autenticado

Conceitualmente, o método é realmente simples. Apenas enviamos um pacote de login e lemos a resposta. Só isso, porque a resposta de "login bem-sucedido" contém as credenciais de todos os usuários, independentemente dos nossos privilégios. Embora já fosse assim no V7, na prática esse método só se tornou útil quando a conta padrão foi introduzida no firmware NVR. A "Default" irremovível não tem privilégios remotos, então você não pode fazer nada com ela. Bem, talvez exceto ler a senha do administrador...

Embora pareça trivial, não foi tão trivial de implementar. Um protocolo personalizado é usado para comunicação, e as senhas são criptografadas usando DES, mas com os bits invertidos (a parte mais difícil foi descobrir isso), com uma chave transmitida pelo servidor. Como não há derivação de chave, um bisbilhoteiro poderia facilmente descriptografar tudo. Ainda assim, é preciso descobrir que os bits estão invertidos ou reimplementar tudo do zero...

Veja a função recover_with_default no arquivo recover.py para a implementação.

Recuperação de senha insegura - o método PSW

Ao analisar o binário, é difícil não notar esse mecanismo. Seu único propósito é... tornar possível a recuperação de senha, e ele realmente faz isso bem. Bem demais, eu diria...

O que está acontecendo aqui? Acho que isso era para ser um mecanismo de recuperação de senha, presumivelmente criado para que os fornecedores pudessem fornecer uma maneira de os proprietários de dispositivos recuperarem suas senhas.

Posso supor que o fluxo deveria ser assim:

  1. Você informa seu e-mail ou telefone ao configurar o dispositivo
  2. Você pede à Tiandy para recuperar sua senha
  3. A Tiandy envia um "pacote mágico" ao seu dispositivo e obtém um e-mail/telefone e um dado criptografado para derivar o código de segurança.
  4. A Tiandy descriptografa e deriva o código de segurança e o envia por esse canal de comunicação.
  5. Você insere esse código de segurança no seu programa cliente, que envia um segundo pacote.
  6. Voilà. O cliente descriptografa a resposta e mostra as credenciais.

Tudo isso é ótimo, exceto que falta uma coisa... onde está a segurança? Em lugar nenhum, ao que parece. Não há nada que nos impeça de enviar esse pacote, derivar o código de segurança e recuperar a senha de qualquer dispositivo acessível.

Acho isso surpreendente, porque não é que haja alguma falha no mecanismo que anule a segurança. Simplesmente não há segurança alguma. Não há nada para corrigir, mas isso também não me parece uma backdoor óbvia. Isso deixa rastros nos logs e tem 3 esquemas diferentes de derivação, cada um mais sofisticado que o anterior. Isso realmente levou tempo para implementar...

Voltando ao método: para que isso funcione, o dispositivo precisa ter um telefone/e-mail associado. Olhando a versão mais antiga, vi que apenas o administrador pode fazer isso, mas então encontrei um bypass. Surpreendentemente, no firmware mais novo, esse bypass não é mais necessário, pois é explicitamente possível alterar o e-mail do dispositivo sem autenticação. Agora, é aqui que acho que a backdoor deveria estar :)

No lado técnico, esse mecanismo é bastante complicado e foi o mais difícil de fazer engenharia reversa e reimplementar. Existem 3 versões desse mecanismo, cada uma usa um algoritmo diferente para derivar o código de segurança. Além do DES com bits invertidos, uma cifra de substituição personalizada com uma chave fixa está envolvida. Mas tudo isso é em vão, porque a Tiandy não consegue tornar segura uma criptografia simétrica com chave fixa, por mais que tente.

Uma coisa que observei é que, como o código de segurança muda a cada minuto, há a possibilidade de o processo original falhar simplesmente porque o código mudou entre o pacote do passo 3 e o do passo 5, não importa quão pouco tempo tenha passado entre o envio deles. Levei isso em consideração, então meu script tenta o processo novamente se o código se mostrar inválido.

Todo o processo, incluindo definir o e-mail (que não precisamos possuir), está implementado no arquivo recover.py.

O bypass de autenticação da API web

Este funciona com versões de firmware mais recentes (2019 e posteriores) que têm a interface web "moderna" (aquela com o "mapa". Gosto desse mapa, embora a Austrália pareça um pouco distorcida).

Este bypass é simples. Embora a maioria dos endpoints da API seja autenticada, há algumas exceções. No entanto, a verificação de se deve pular a autenticação e a correspondência de qual endpoint ativar são implementadas em lugares diferentes. Na maioria dos casos, a autenticação é ignorada quando o caminho da URL é igual a uma determinada string, o que é seguro.

Mas versões recentes introduzem outra exceção, que é ativada quando as strings Record/DownLoad e ID= simplesmente existem em algum lugar no caminho da URL.

Agora, para endpoints onde o caminho completo é comparado, isso ainda é seguro. Como Security/users é um desses endpoints, não podemos recuperar a senha diretamente. Para nossa sorte, o endpoint de exportação de configuração é selecionado verificando se o caminho da URL começa com uma determinada string (usando strncmp), então podemos simplesmente adicionar essas strings ao caminho e exportar o arquivo de configuração.

Recuperar a senha usando essa falha está implementado em cgi_recover.py.

Além da recuperação de senha

Teoricamente, o administrador pode atualizar o firmware, e o firmware não é assinado nem criptografado. Mas será que realmente precisamos preparar um pacote de firmware personalizado? Às vezes não. Às vezes sim, e eu fui louco o suficiente para realmente implementá-lo...

Para firmware NVR antigo

Se você tiver a senha, há uma vulnerabilidade de injeção de comandos que você pode usar, o script ftpupdate.py. O que acontece é que dizemos ao dispositivo para buscar uma atualização via ftp e ftpget é usado para executar essa tarefa. Como era de se esperar, nossos parâmetros vão diretamente para a função system().

Firmware mais recente

No firmware NVR, o protocolo binário tem o comando FILETRANSPORT, que faz exatamente o que o nome diz. Na verdade, não há mais nada a dizer, porque você poderia simplesmente baixar o SDK e usar o mesmo comando. Claro que eu quis reimplementá-lo, então para ver como isso funciona, olhe filetransport.py.

Modelos IPC não têm esse comando, porém, como eu disse antes, sempre podemos atualizar o firmware. Embora preparar toda a flash seja impraticável, os pacotes de atualização da Tiandy nos permitem substituir arquivos individuais, que é exatamente o que precisamos (veja descompactação do firmware).

Exceto que não é tão simples. O formato de arquivo "box" tem alguns metadados e depois uma matriz de arquivos. O primeiro arquivo deve ser nomeado ProductModule e deve conter parâmetros de dispositivo correspondentes, caso contrário a atualização não prosseguirá. Precisamos não apenas dos valores desses parâmetros, mas também dos próprios parâmetros. Além disso, a parte dos metadados (incluindo a versão do arquivo box) também é verificada.

Montar isso manualmente parece impraticável, mas felizmente há outro caminho. As exportações de arquivo de configuração usam o mesmo formato de arquivo "box", com todos os metadados correspondentes e o arquivo ProductModule incluído, exceto o campo de tipo de atualização.

Consegui descobrir como preencher esse campo e, portanto, implementar esse processo. Embora o mecanismo também esteja presente no firmware NVR, ele não funciona da mesma forma; no entanto, não faz sentido analisar mais, já que os NVRs têm o comando FILETRANSPORT descrito anteriormente.

O script upgrade_rw.py faz uso do processo de atualização. O nome sugere algo mais, porém... Isso porque, ao exportar o arquivo de configuração, especificamos quais arquivos exportar pelo nome e, como era de se esperar, qualquer arquivo funciona, então podemos baixar o box e então ler esse arquivo usando o mesmo código usado para extrair o firmware.

Tanto a exportação quanto a atualização também podem ser feitas via API web. Nesse caso, não é possível ler arquivos arbitrários. Ainda assim, quis implementar isso porque a API parece mais estável; veja cgi_recover.py.

O que não analisei

Em modelos que suportam FTP, pode ser possível injetar comandos shell na senha do usuário (quando um comando é executado e adiciona esse usuário para que ele possa fazer login via FTP).

Encontrando dispositivos Tiandy na internet

Dispositivos Tiandy têm a porta 3001 aberta. Essa é a porta necessária para executar os métodos não-web. Modelos mais novos têm RTSP na porta 9100 além da porta 554, e também têm RTMP na porta 1935. Modelos IPC usam a porta 8082 para ONVIF. HTTP e HTTPS rodam nas portas padrão.

Dispositivos com a interface web antiga (usando nossa amada tecnologia ActiveX) contêm um dos seguintes em sua resposta HTTP:

root@kitploit:~
<title>Net Video Browser</title>
root@kitploit:~
tdvideo.css

Dispositivos com a interface web mais nova (desta vez usando... Flash) contêm isto na resposta:

root@kitploit:~
res/app-0.1.0.css

(o cabeçalho Last-Modified fica feliz em nos revelar a data exata do lançamento)

Também podemos identificar esses dispositivos pelo certificado, embora HTTPS nem sempre esteja habilitado. Existem apenas dois certificados usados em todos os dispositivos e eles podem ser encontrados no firmware baixado, o que torna inútil o pinning deles.

O mais antigo:

root@kitploit:~
C=CN, ST=Tianjin, O=Tiandy Tech, CN=dvr_ui

O mais novo:

root@kitploit:~
C=CN, ST=Tianjin, L=Tianjin, O=Tiandy Tech Ltd, CN=NetDevice

A propósito... o suporte a HTTPS é implementado via um processo stunnel separado. Isso funciona, mas como era de se esperar, o endereço IP se perde no processo, então os logs sempre dizem 127.0.0.1.

URLs RTSP e RTMP da Tiandy

A Tiandy afirma que seus dispositivos suportam RTSP e RTMP. Isso é legal, mas o que não encontramos no manual é como realmente usar esses protocolos, porque não encontramos as URLs RTSP e RTMP necessárias. Felizmente, tenho essa informação como subproduto da análise, então posso compartilhá-la.

URLs RTSP

Para NVR:
Para ver o stream ao vivo do canal C (começando em 1) com o tipo de stream S (1, 2, 3):

root@kitploit:~
rtsp://username:password@host/C/S

Para IPC:
Para ver o stream ao vivo com o tipo de stream S:

root@kitploit:~
rtsp://username:password@host/S

URLs RTMP

As URLs RTMP não são tão simples porque exigem um hash personalizado para que a solicitação possa ser autenticada. No entanto, o RTMP também nos permite reproduzir o conteúdo gravado.

A url para o stream ao vivo é:

root@kitploit:~
rtmp://host/live/C/S/authstring

onde C é o canal, S é o tipo de stream.

A url para reprodução é:

root@kitploit:~
rtmp://host/vod/START-STOP/C/S/authstring

onde START e STOP são timestamps unix.

authstring é calculada da seguinte forma:

root@kitploit:~
base64("username:"+md5("username:password")+":unix_timestamp")

A ferramenta rtmpauth.py pode gerá-la:

root@kitploit:~
python3 rtmpauth.py username password

Como esse timestamp é verificado e a diferença não pode ser maior que 2 dias, há limitações:

  • a câmera precisa estar com a hora correta configurada
  • uma URL RTMP deixará de funcionar após 2 dias

Descompactando o firmware

Atualizações de firmware são empacotadas em um formato de arquivo "box" proprietário que não é assinado nem criptografado. Esse formato é na verdade muito simples do ponto de vista do descompactador. Há um cabeçalho que ignoramos e uma matriz de arquivos para descompactar, onde cada arquivo tem um cabeçalho de tamanho fixo contendo nome do arquivo e tamanho (duas vezes), e então os dados seguem.

A ferramenta unbox.py descompacta o arquivo em um diretório com o nome do arquivo box ou no diretório especificado:

root@kitploit:~
python3 unbox.py [box_file]
python3 unbox.py [box_file] [target_dir]

Esta ferramenta deve ser segura de usar (escrevi esta linha, depois verifiquei a ferramenta novamente e encontrei uma vulnerabilidade... ops) porque caminhos absolutos são transformados em relativos, .. é substituído por __ e não há symlinks.

Às vezes você precisará executar esta ferramenta duas vezes, pois notará que o arquivo dentro de um .box é outro .box.

Baixar ferramenta