NetCatTest

Segurança em PDV & Varejo

Segurança em PDV: vulnerabilidades, ataques e testes práticos

Análise técnica de sistemas PDV, TEF e Pix: integração com pinpads como o Gertec PPC930, APIs, SQL injection, DLLs e conciliação, com comandos e demonstrações em Python.

Por Daniel Felipe 09/09/2026 24 min leitura

Um sistema PDV concentra dinheiro, identidade de operadores, estoque, documentos fiscais e integrações de pagamento em uma máquina que precisa funcionar durante todo o expediente. Quando o software do caixa confia demais no Windows, na rede local ou em uma resposta recebida do navegador, o impacto pode aparecer como venda adulterada, acesso a outra filial, indisponibilidade ou conciliação financeira incorreta.

No varejo brasileiro, existe uma oferta ampla de sistemas de frente de caixa gratuitos ou com planos gratuitos, disponíveis para instalação rápida. O cenário que merece atenção é a empresa baixar o programa, instalar drivers, conectar um pinpad como o Gertec PPC930 e considerar a integração segura porque uma venda de teste foi aprovada. A aprovação demonstra funcionamento daquele fluxo; não avalia autenticação, autorização, integridade do instalador ou resistência a adulteração.

Este guia examina a arquitetura de PDV, TEF e Pix, apresenta nove classes de ataque e inclui três demonstrações locais completas. Os exemplos usam dados fictícios e não dependem de adquirente, cartão ou pinpad físico.

PDV gratuito é vulnerável? O problema está na cadeia de confiança

Gratuito, comercial e open source são modelos de distribuição distintos, não resultados de auditoria. Um projeto aberto e mantido pode oferecer controles melhores que um produto pago abandonado. O risco surge quando não há procedência verificável, atualização confiável, separação de privilégios ou responsável por corrigir falhas.

Há fornecedores brasileiros que anunciam versões gratuitas de PDV, como o Consumer. Essa referência comprova a existência da modalidade; não indica vulnerabilidade nesse fornecedor, compatibilidade com determinado pinpad nem prevalência de instalações inseguras. A análise abaixo trata de padrões de arquitetura que devem ser verificados em cada implantação.

Antes de discutir exploração, identifique quem fornece o executável, quem atualiza o middleware, onde ficam as credenciais do integrador e quem possui acesso remoto ao caixa. Um instalador autêntico pode entregar uma configuração fraca; um software bem desenvolvido pode ser instalado com permissões excessivas. São problemas diferentes e pedem evidências diferentes.

Checklist
  • Origem do instalador e canal oficial de atualização identificados.
  • Versão do PDV, middleware e driver registrada por estação.
  • Conta de operador separada da administração do Windows.
  • Diretórios de programa protegidos contra gravação pelo operador.
  • Serviços locais com identidade, porta e finalidade conhecidas.
  • Credenciais de produção separadas das credenciais de teste.
  • Confirmação de pagamento feita pelo backend com dados do provedor.

Como PDV, TEF, Pix e pinpad se conectam

PDV é a aplicação que conduz a venda. TEF é a integração que coordena operações de transferência eletrônica de fundos. O pinpad é o periférico de interação com o cartão e o portador. Um POS autônomo pode reunir várias funções no mesmo dispositivo; um pinpad ligado por USB normalmente participa de uma arquitetura com um computador hospedeiro.

A documentação do PPC930 informa interfaces USB e serial e recursos para cartões e criptografia. Esses recursos não tornam automaticamente confiável o software instalado no computador. Uma exposição no serviço que conversa com o periférico é uma descoberta sobre esse serviço e sua configuração; não basta para afirmar quebra da proteção criptográfica do pinpad.

Código
Operador
  -> PDV: carrinho, descontos, fechamento e identidade da loja
      -> Backend: pedidos, permissoes e conciliacao
      -> Integrador TEF / middleware
          -> Driver / USB / serial -> pinpad
          -> Provedor de pagamento / adquirente

Pix integrado
  -> Backend cria cobranca no PSP
  -> PDV exibe QR Code retornado pelo fluxo
  -> Backend confirma recebimento e concilia o pedido

O ponto decisivo é localizar as fronteiras de confiança: interface para backend, processo para serviço local, loja para outra loja, pedido para recebimento. Pergunte qual componente pode alterar cada dado e qual componente toma a decisão final. O preço enviado pela interface, por exemplo, não deve substituir o cálculo autorizado do servidor.

Nove tipos de ataque contra sistemas PDV

SuperfíciePré-condição relevantePossível impactoEvidência a buscar
Instalador e atualizadorOrigem ou integridade não verificadasExecução de código no caixaAssinatura, hash confiável e mecanismo de atualização
DLLs e serviçosCaminho gravável e carga de código pelo processoExecução com os privilégios do serviçoACL efetiva e módulo realmente carregado
API localOperação sensível sem autenticação adequadaControle indevido da integraçãoRequisição reproduzível e mudança de estado correlacionada
API entre lojasFalta de autorização por objetoLeitura ou alteração de pedidos de outra filialComparação com identidades e objetos conhecidos
Entrada SQLConcatenação de dados em consultasConsulta adulterada e acesso indevidoConsulta reproduzida com base fictícia
Pix e conciliaçãoConfiança no cliente ou evento sem verificaçãoBaixa indevida, divergência ou duplicaçãoRecebimento autenticado versus pedido e estado
Suporte remotoConta compartilhada ou sessão excessivamente privilegiadaAcesso inicial e movimento lateralIdentidade, origem, duração e ações da sessão
Periféricos USBDispositivo com classe inesperada aceitoEntrada de teclado ou interface de rede indevidaInventário PnP e eventos de conexão
Malware e disponibilidadeExecução prévia ou fluxo sem recuperaçãoAdulteração, parada de caixa e perda de operaçãoProcessos, módulos, conexões e histórico transacional

Uma porta aberta não demonstra fraude. Uma ACL permissiva não prova que uma DLL foi carregada. Um evento duplicado não prova pagamento duplicado. O relatório técnico deve ligar pré-condição, comportamento observado e impacto, sem pular essas etapas.

1. Inventário do caixa: processos, portas, serviços e pinpad

Comece pelo Windows do PDV. Os comandos desta seção são para PowerShell; os caminhos são exemplos que devem corresponder à instalação examinada. Eles coletam estado, sem reiniciar serviços ou enviar comandos ao dispositivo de pagamento.

Código
Get-CimInstance Win32_SerialPort |
    Select-Object DeviceID, Name, PNPDeviceID

Get-PnpDevice -PresentOnly |
    Where-Object { $_.FriendlyName -match 'Gertec|PPC930|Pin.?Pad' } |
    Select-Object Status, Class, FriendlyName, InstanceId

Get-CimInstance Win32_Service |
    Where-Object { $_.Name -match 'PDV|TEF|Gertec' -or $_.DisplayName -match 'PDV|TEF|Gertec' } |
    Select-Object Name, State, StartName, PathName

Get-NetTCPConnection -State Listen |
    Sort-Object LocalPort |
    Select-Object LocalAddress, LocalPort, OwningProcess

Os filtros por nome são triagem: serviços com outro nome podem ficar de fora, e nem todo pinpad será exposto como porta serial. Cruze o PID da porta com o executável e com a conta do serviço. Uma escuta em 0.0.0.0 ou :: indica associação a todas as interfaces daquela família, mas a acessibilidade remota ainda depende de firewall e roteamento. Uma escuta em loopback reduz exposição de rede e continua acessível a outros processos locais.

Para uma estação de teste conhecida, um inventário TCP direcionado ajuda a comparar o que está escutando com o que outra máquina alcança. O endereço abaixo representa um único host da rede de laboratório; não há varredura de uma faixa inteira.

Terminal Linux
nmap -sT -sV --version-light -T2 -p 135,139,445,3389,8080,8443 192.168.56.20

Uma porta 3389 acessível aponta para uma superfície de administração remota, não para credencial fraca comprovada. Uma porta 8080 não identifica, por si, o middleware do fabricante. Registre serviço, versão observada, origem do teste e regra de acesso esperada.

2. Instaladores, DLL hijacking e permissões excessivas

Um caminho de comprometimento pode começar antes da primeira venda: instalador obtido de um espelho desconhecido, atualização sem verificação ou componente colocado em um diretório gravável pelo operador. Se um processo privilegiado carrega uma biblioteca controlável a partir desse diretório, a gravação deixa de ser apenas um problema de organização de arquivos.

O MITRE ATT&CK documenta abuso de DLLs, incluindo substituição e manipulação da ordem de busca. Para confirmar um caso no PDV, é necessário demonstrar a resolução e a carga do módulo, além da permissão de gravação. Não basta localizar um arquivo com extensão DLL na pasta do programa.

Código
$instalador = 'C:\Auditoria\instalador-pdv.exe'
Get-FileHash -LiteralPath $instalador -Algorithm SHA256
Get-AuthenticodeSignature -LiteralPath $instalador |
    Select-Object Status, StatusMessage, SignerCertificate

Get-ChildItem -LiteralPath 'C:\PDV' -Filter *.dll -File |
    ForEach-Object {
        $assinatura = Get-AuthenticodeSignature -LiteralPath $_.FullName
        [pscustomobject]@{
            Arquivo = $_.FullName
            Estado = $assinatura.Status
        }
    }
Prompt de comando
icacls "C:\PDV"
icacls "C:\PDV\bin"
whoami /groups

Compare o SHA-256 com um valor obtido por um canal confiável; calcular um hash sozinho não autentica a origem. Uma assinatura válida identifica um signatário e ajuda a verificar integridade, mas não prova ausência de vulnerabilidades. Já NotSigned não é sinônimo de malware. O Get-AuthenticodeSignature fornece dados para essa análise, não um veredito completo.

Em ACLs, avalie entradas de modificação ou controle total concedidas a grupos amplos, herança e acesso efetivo do usuário. Separe binários de dados mutáveis: o operador pode precisar gravar um arquivo de operação, mas não substituir o executável do serviço. A correção deve preservar as permissões necessárias ao integrador e ser validada com o fluxo de venda.

3. API local: localhost não substitui autenticação

Alguns desenhos de integração expõem uma API HTTP local para intermediar periféricos. Outros usam DLLs, sockets ou troca de arquivos. A superfície depende da implementação instalada; não há neste artigo a afirmação de que uma porta ou endpoint específico pertence ao PPC930.

Em uma API local, examine quem pode chamar a operação, como a sessão é vinculada ao caixa e se operações de estado aceitam chamadas repetidas. Um serviço que aceita comandos de qualquer processo do usuário precisa de um modelo explícito de confiança. Se a API também é acessível pelo navegador, analise origem, formatos aceitos e proteção contra requisições de páginas não confiáveis.

O controle de acesso também precisa ser granular. Consultar o estado de uma sessão, abrir uma transação e encerrar uma operação não têm necessariamente a mesma autorização. Uma resposta HTTP 200 apenas informa que a camada HTTP respondeu; a conclusão exige observar o estado funcional e os identificadores da transação.

4. Demonstração de BOLA: pedido de outra loja

Em um backend com múltiplas filiais, autenticar o operador não significa autorizar todos os pedidos. A falha BOLA ocorre quando a API recebe um identificador válido e entrega o objeto sem verificar seu vínculo com a identidade solicitante. A OWASP descreve essa classe de falha; trocar números sequenciais por UUIDs não substitui a autorização.

Salve o código abaixo como api_pdv_lab.py. Ele usa apenas a biblioteca padrão do Python 3.10 ou superior, escuta em 127.0.0.1:8766 e contém dois pedidos fictícios. Os tokens demo-loja-a e demo-loja-b são identificadores fixos de demonstração, não um mecanismo de autenticação para produção.

Código
import json
from http.server import BaseHTTPRequestHandler, HTTPServer

PEDIDOS = {
    '100': {'loja': 'A', 'total_centavos': 12990},
    '200': {'loja': 'B', 'total_centavos': 4500},
}
TOKENS_DEMO = {'demo-loja-a': 'A', 'demo-loja-b': 'B'}

class API(BaseHTTPRequestHandler):
    def responder(self, status, corpo):
        dados = json.dumps(corpo).encode()
        self.send_response(status)
        self.send_header('Content-Type', 'application/json')
        self.send_header('Content-Length', str(len(dados)))
        self.end_headers()
        self.wfile.write(dados)

    def do_GET(self):
        token = self.headers.get('Authorization', '').removeprefix('Bearer ')
        loja = TOKENS_DEMO.get(token)
        if loja is None:
            return self.responder(401, {'erro': 'autenticacao'})
        partes = self.path.strip('/').split('/')
        if len(partes) != 3 or partes[1] != 'pedidos':
            return self.responder(404, {'erro': 'rota'})
        modo, _, pedido_id = partes
        if modo not in ('vulneravel', 'corrigido'):
            return self.responder(404, {'erro': 'rota'})
        pedido = PEDIDOS.get(pedido_id)
        if pedido is None:
            return self.responder(404, {'erro': 'pedido'})
        if modo == 'corrigido' and pedido['loja'] != loja:
            return self.responder(403, {'erro': 'loja_nao_autorizada'})
        self.responder(200, pedido)

if __name__ == '__main__':
    print('API ficticia em http://127.0.0.1:8766', flush=True)
    HTTPServer(('127.0.0.1', 8766), API).serve_forever()
Terminal Linux
python api_pdv_lab.py

Em outro terminal, compare os dois caminhos com a mesma identidade da loja A e o pedido 200, que pertence à loja B:

Terminal Linux
curl -i -H "Authorization: Bearer demo-loja-a" http://127.0.0.1:8766/vulneravel/pedidos/200
curl -i -H "Authorization: Bearer demo-loja-a" http://127.0.0.1:8766/corrigido/pedidos/200
curl -i -H "Authorization: Bearer demo-loja-a" http://127.0.0.1:8766/corrigido/pedidos/100

No Windows, use curl.exe para evitar o alias de versões antigas do PowerShell. A primeira chamada retorna HTTP 200 com o pedido de outra loja; a segunda retorna HTTP 403; a terceira retorna HTTP 200 porque o objeto pertence à identidade autenticada. Esses resultados foram verificados no exemplo local.

Em produção, a loja deve vir da sessão validada no servidor. Aceitar loja_id do corpo da requisição e usá-lo como prova de autorização apenas muda o lugar do problema. A validação também deve considerar função: visualizar um pedido não implica poder cancelar, estornar ou conceder desconto.

5. Demonstração de SQL injection no cadastro de produtos

Um leitor de código de barras entrega entrada para a aplicação; isso não transforma o conteúdo lido em dado confiável. Campos de SKU, busca e importação podem alcançar consultas SQL. Se o código concatena a entrada à consulta, caracteres destinados a representar um produto podem ser interpretados como instrução SQL.

Este exemplo cria uma base SQLite apenas em memória. Salve como sqli_pdv.py e execute com Python. A consulta vulnerável e a parametrizada recebem exatamente a mesma entrada.

Código
import sqlite3

db = sqlite3.connect(':memory:')
db.execute('CREATE TABLE produtos (sku TEXT, nome TEXT, preco_centavos INTEGER)')
db.executemany('INSERT INTO produtos VALUES (?, ?, ?)', [
    ('1001', 'Cafe', 1590),
    ('1002', 'Arroz', 2490),
])

def vulneravel(sku):
    sql = "SELECT sku, nome FROM produtos WHERE sku = '" + sku + "'"
    return db.execute(sql).fetchall()

def parametrizada(sku):
    return db.execute('SELECT sku, nome FROM produtos WHERE sku = ?', (sku,)).fetchall()

entrada = "1001' OR 1=1 -- "
print('Busca normal:', vulneravel('1001'))
print('Concatenacao:', vulneravel(entrada))
print('Parametros:', parametrizada(entrada))
assert len(vulneravel(entrada)) == 2
assert parametrizada(entrada) == []
Terminal Linux
python sqli_pdv.py
Código
Busca normal: [('1001', 'Cafe')]
Concatenacao: [('1001', 'Cafe'), ('1002', 'Arroz')]
Parametros: []

A entrada modifica a condição da primeira consulta e amplia o conjunto retornado. Na segunda, permanece um valor de busca e não encontra produto correspondente. Esse resultado demonstra adulteração de uma consulta no programa de exemplo; não demonstra extração de dados de um PDV comercial.

A parametrização de consultas deve ser aplicada na camada que acessa o banco. Validação de formato continua útil para regras de negócio, mas uma expressão regular no frontend não substitui esse controle. Nomes dinâmicos de coluna e ordenação exigem listas explícitas de opções permitidas, pois não são tratados como valores por todos os mecanismos de parâmetros.

6. Pix: QR Code exibido não significa recebimento liquidado

Em um fluxo mal implementado, o PDV recebe um QR Code, abre uma tela de espera e confia em uma resposta local como pago=true. Um atacante que controla a interface ou uma integração intermediária pode tentar adulterar essa indicação. O backend deve decidir a baixa a partir de informação autenticada do provedor e da correspondência com o pedido.

A especificação oficial da API Pix define recursos funcionais, e o próprio repositório separa esse escopo dos requisitos dos manuais de segurança. O formato de autenticação e de notificações deve seguir a integração do PSP contratado. Não existe um cabeçalho HMAC universal que possa ser inventado pelo PDV e tratado como padrão do Pix.

Há dois problemas distintos: adulterar o destinatário apresentado ao pagador e enganar a conciliação do comerciante. O primeiro exige proteger a origem e a integridade do conteúdo exibido; o segundo exige conferir o recebimento no backend. Verificar apenas um texto na tela, um comprovante ou o CRC do payload do QR Code não autentica uma liquidação.

Campo ou relaçãoVerificação no backend
PedidoExiste e pertence à loja autenticada
ValorCorresponde ao valor esperado na política de pagamento
RecebedorCorresponde à conta ou ao estabelecimento esperado
Identificador de cobrançaEstá vinculado à tentativa de pagamento correta
Identificador de recebimentoAinda não foi apropriado por outro pedido
EstadoPermite a transição solicitada
Origem da informaçãoFoi autenticada segundo o contrato do provedor

Use valores monetários inteiros em centavos ou um tipo decimal apropriado. O exemplo seguinte adota pagamento integral único; parcelamento, pagamento parcial, devolução e múltiplas tentativas exigem um modelo mais rico.

7. Demonstração de conciliação e proteção contra replay

Salvar um identificador depois de marcar a venda como paga deixa uma janela de inconsistência. Duas entregas de um mesmo evento podem disputar o processamento. A unicidade e a mudança de estado precisam ser garantidas no armazenamento transacional, e não apenas em uma variável de memória do servidor.

Salve como conciliacao_pdv.py. O objeto recibo representa o resultado já autenticado de uma consulta ao PSP. O código não implementa transporte, autenticação do provedor nem um endpoint de webhook; concentra o teste nas regras de conciliação. A base é fictícia e fica em memória.

Código
import sqlite3

db = sqlite3.connect(':memory:', isolation_level=None)
db.executescript('''
CREATE TABLE pedidos (
    id TEXT PRIMARY KEY, txid TEXT UNIQUE, valor_centavos INTEGER,
    recebedor TEXT, estado TEXT
);
CREATE TABLE recebimentos (
    provedor TEXT, id TEXT, pedido_id TEXT UNIQUE,
    PRIMARY KEY (provedor, id)
);
INSERT INTO pedidos VALUES ('P100', 'TX-DEMO-100', 12990, 'LOJA-A', 'PENDENTE');
''')

def conciliar(pedido_id, recibo):
    # recibo representa uma consulta autenticada ao PSP, nao o body do cliente.
    db.execute('BEGIN IMMEDIATE')
    try:
        pedido = db.execute('SELECT * FROM pedidos WHERE id = ?', (pedido_id,)).fetchone()
        if pedido is None:
            raise ValueError('pedido inexistente')
        _, txid, valor, recebedor, estado = pedido
        if (recibo['txid'], recibo['valor_centavos'], recibo['recebedor']) != (txid, valor, recebedor):
            raise ValueError('divergencia na conciliacao')
        if recibo['estado'] != 'LIQUIDADO':
            raise ValueError('recebimento ainda nao liquidado')
        anterior = db.execute(
            'SELECT pedido_id FROM recebimentos WHERE provedor = ? AND id = ?',
            (recibo['provedor'], recibo['id']),
        ).fetchone()
        if anterior:
            if anterior[0] != pedido_id:
                raise ValueError('recebimento pertence a outro pedido')
            db.execute('COMMIT')
            return 'REPETICAO_IGNORADA'
        if estado != 'PENDENTE':
            raise ValueError('transicao de estado invalida')
        db.execute('INSERT INTO recebimentos VALUES (?, ?, ?)',
                   (recibo['provedor'], recibo['id'], pedido_id))
        db.execute("UPDATE pedidos SET estado = 'PAGO' WHERE id = ?", (pedido_id,))
        db.execute('COMMIT')
        return 'PAGO'
    except Exception:
        db.execute('ROLLBACK')
        raise

recibo = dict(provedor='PSP-DEMO', id='E2E-DEMO-100', txid='TX-DEMO-100',
              valor_centavos=12990, recebedor='LOJA-A', estado='LIQUIDADO')
for campo, valor in [('valor_centavos', 1), ('recebedor', 'LOJA-B'), ('estado', 'PENDENTE')]:
    try:
        conciliar('P100', {**recibo, campo: valor})
        raise AssertionError('entrada invalida foi aceita')
    except ValueError as erro:
        print(campo, '-> REJEITADO:', erro)
print(conciliar('P100', recibo))
print(conciliar('P100', recibo))
assert db.execute('SELECT count(*) FROM recebimentos').fetchone()[0] == 1
Terminal Linux
python conciliacao_pdv.py
Código
valor_centavos -> REJEITADO: divergencia na conciliacao
recebedor -> REJEITADO: divergencia na conciliacao
estado -> REJEITADO: recebimento ainda nao liquidado
PAGO
REPETICAO_IGNORADA

O teste verifica divergência de valor, recebedor incorreto, estado pendente e repetição. A chave composta identifica um recebimento no provedor; a restrição por pedido representa a política de pagamento único. BEGIN IMMEDIATE e o commit agrupam registro e mudança de estado no SQLite. A versão de produção deve usar uma base persistente, política de retry, tratamento de conflitos e observabilidade.

Mesmo um evento autêntico pode estar atrasado. Depois de timeout, não crie outra cobrança cegamente: consulte a tentativa anterior e reconcilie o estado. A autorização transacional precisa estar ligada aos dados e ao estado da operação, não apenas ao fato de o usuário ter feito login.

8. Suporte remoto e segmentação da rede de caixas

O acesso remoto do fornecedor pode ser um caminho administrativo legítimo e, ao mesmo tempo, uma superfície crítica. Contas compartilhadas, sessões permanentes e permissões de administrador transformam o comprometimento de uma credencial em acesso a várias estações. A pergunta técnica é quais recursos essa identidade consegue alcançar e como suas ações são atribuídas.

Uma VLAN de PDVs deve ter regras de fluxo, não apenas um nome diferente. Caixas não precisam, por padrão, conversar livremente com todo o escritório, a rede de convidados e interfaces de administração. A política deve ser construída a partir dos destinos necessários ao PDV, ao integrador, à resolução de nomes, à atualização e ao suporte controlado.

Código
Get-NetFirewallProfile |
    Select-Object Name, Enabled, DefaultInboundAction, DefaultOutboundAction

Get-SmbShare |
    Select-Object Name, Path, Description

Get-CimInstance Win32_Service |
    Where-Object { $_.StartName -eq 'LocalSystem' } |
    Select-Object Name, State, PathName

Esses comandos são um ponto de partida. As políticas efetivas também podem vir de domínio, MDM e regras no equipamento de rede. Uma política local com firewall ativo não prova isolamento entre filiais. Valide a comunicação permitida a partir das origens relevantes e compare com a matriz de acesso documentada.

9. USB, malware de PDV e disponibilidade operacional

Um dispositivo USB pode se apresentar como teclado, armazenamento, porta serial ou placa de rede. O formato físico do conector não informa a classe do dispositivo. Em uma estação desbloqueada, a aceitação indiscriminada de periféricos pode abrir caminhos de entrada que a equipe não associou à operação do caixa.

Controle físico, inventário de dispositivos e regras por classe e identidade ajudam a reduzir essa superfície. O teste deve considerar os equipamentos realmente usados: pinpad, scanner, impressora e assistência técnica. Uma política que bloqueia todos os USB indiscriminadamente pode impedir a própria operação que deveria proteger.

Malware voltado a pagamentos também é uma realidade documentada. Em 2023, a Kaspersky descreveu variantes do Prilex que bloqueavam transações por aproximação em sistemas infectados para induzir o uso do cartão físico. É uma referência histórica de pesquisa; não prova infecção atual, vulnerabilidade do PPC930 ou quebra geral de pagamentos contactless.

Da mesma forma, RAM scraping depende de dados sensíveis estarem acessíveis no processo comprometido. Não se deve assumir que o computador recebe PAN completo ou PIN em claro em toda arquitetura. A avaliação precisa mapear o fluxo real de dados e a solução de proteção implantada. Um ataque pode comprometer lógica de venda ou disponibilidade sem extrair informações criptográficas do dispositivo.

Falhas de estado merecem a mesma atenção que injeções: cabo desconectado durante a operação, timeout, callback atrasado e reinício do processo podem deixar pedidos pendentes. Reiniciar um serviço e observar a tela voltar não comprova reconciliação. O sistema precisa reconhecer a tentativa anterior, preservar o identificador e resolver o resultado antes de aceitar uma nova cobrança.

EventoComportamento a verificar
Duplo clique em pagarUma intenção lógica e controle de concorrência
Timeout do integradorConsulta de estado antes de repetir a operação
Queda do PDVRecuperação de tentativas pendentes ao iniciar
Evento duplicadoProcessamento idempotente
Cancelamento localEstado confirmado no fluxo correspondente
Resposta tardiaAssociação à tentativa correta, sem baixar outra venda
Perda de redeEstado explícito de incerteza e reconciliação posterior

Telemetria: como investigar o que aconteceu no caixa

Procure relações entre processo, arquivo, rede e operação comercial. Uma conexão desconhecida fica mais útil quando associada ao executável que a iniciou, ao horário de atualização e à sessão do operador. Um estorno sem trilha de autorização pode ser mais relevante que uma lista extensa de portas.

Com o Sysmon instalado e configurado, eventos de criação de processo, conexão de rede, carga de imagem e criação de arquivo ajudam nessa correlação. A disponibilidade depende da configuração: carga de imagem e conexões não devem ser presumidas habilitadas. A consulta abaixo lê eventos já existentes.

Código
$inicio = (Get-Date).AddHours(-4)
Get-WinEvent -FilterHashtable @{
    LogName = 'Microsoft-Windows-Sysmon/Operational'
    StartTime = $inicio
    Id = 1, 3, 7, 11
} -ErrorAction Stop |
    Select-Object TimeCreated, Id, Message

Ausência de evento pode significar ausência de coleta, retenção insuficiente ou filtro de configuração. Não é um atestado de ausência de ataque. Para o fluxo financeiro, registre identificador do pedido, tentativa, loja, estação, operação, decisão e código de resultado. Credenciais, PIN, CVV e trilhas de cartão não pertencem ao log de diagnóstico.

Nos requisitos de pagamento, diferencie a avaliação do dispositivo, do software e do ambiente. O PCI DSS trata da proteção de dados de conta; ter um periférico com certificações não substitui a análise de escopo da implantação. A configuração exata da solução e as responsabilidades dos participantes precisam ser consideradas.

Como transformar a análise em um relatório técnico útil

Descreva cada achado com o mínimo necessário para outra pessoa reproduzir e corrigir: versão, componente, identidade utilizada, entrada, resposta, estado antes e depois e condição de sucesso. Evite agrupar “PDV vulnerável” como se fosse uma descoberta única. O proprietário da correção pode ser o desenvolvedor do caixa, o integrador, a infraestrutura ou mais de uma equipe.

Checklist
  • Executável e versão do componente afetado identificados.
  • Pré-condição demonstrada, sem transformar hipótese em fato.
  • Requisição, comando ou código do teste preservado.
  • Resposta e efeito no estado registrados com identificadores fictícios ou saneados.
  • Impacto separado de comportamentos apenas operacionais.
  • Correção proposta na fronteira de confiança responsável.
  • Reteste com resultado esperado, incluindo falha e repetição.
  • Fluxos de venda, cancelamento e recuperação verificados após a mudança.

Os testes locais deste artigo demonstram três problemas específicos: consulta SQL alterada por concatenação, leitura de pedido de outra loja e validação de conciliação com idempotência. Eles não são uma auditoria de hardware nem uma comprovação de falha em um produto comercial. A força de uma análise de Red Team está em transformar essas hipóteses em evidências dentro da arquitetura examinada.

Perguntas frequentes sobre segurança em PDV

Conectar um Gertec PPC930 protege o software do caixa?

O pinpad participa do processamento de pagamento, mas não valida automaticamente o cadastro de produtos, as permissões do operador ou a autorização da API do PDV. Avalie cada componente e o fluxo entre eles.

Um sistema PDV gratuito é menos seguro?

O preço não determina segurança. Procedência, manutenção, controles de acesso, integração de pagamentos e configuração da instalação são critérios verificáveis. Não há neste artigo um levantamento estatístico comparando produtos gratuitos e pagos.

Qual é o primeiro teste em um PDV Windows?

Inventariar software, serviços, contas, diretórios e interfaces. Esse mapa permite escolher testes específicos e reconhecer quando um resultado pertence ao PDV, ao integrador ou ao sistema operacional.

Um webhook basta para marcar uma venda como paga?

Somente quando sua origem, dados e semântica forem validados segundo o provedor e a política de conciliação. O processamento deve tolerar repetição, atraso e concorrência, além de conferir o vínculo com o pedido.

Referências técnicas

As referências estão vinculadas às seções correspondentes: Gertec para características do PPC930; OWASP para autorização e SQL injection; Banco Central para API Pix; Microsoft para inspeção e telemetria; MITRE para abuso de DLLs; Kaspersky para o caso histórico Prilex; PCI SSC para segurança de dados de pagamento. Os programas demonstrativos foram escritos para este artigo e usam somente dados fictícios.

Escrito por

Daniel Felipe é criador do NetCatTest e produz conteúdos sobre cibersegurança, privacidade digital, OSINT, laboratórios autorizados e ferramentas para estudo técnico responsável.

Compartilhar

Enviar este artigo